home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PsL Monthly 1993 December
/
PSL Monthly Shareware CD-ROM (December 1993).iso
/
prgmming
/
dos
/
c
/
autolib.exe
/
MANUAL.DOC
< prev
next >
Wrap
Text File
|
1992-03-30
|
187KB
|
5,412 lines
Reference Manual for the
AutoLibrary(tm) Program-Playback Tool
Version 1.2
March 1992
Copyright 1991 by
Wayne E. McDaniel
All Rights Reserved
AutoLibrary(tm) is a Trademark of
Avid Software
Avid Software
P.O. Box 1871
Beaverton, OR 97075-1871
(503) 626-6652
CompuServe Mail: 70372,2513
Internet: 70372.2513@compuserve.com
_______
____|__ | (tm)
--| | |-------------------
| ____|__ | Association of
| | |_| Shareware
|__| o | Professionals
-----| | |---------------------
|___|___| MEMBER
Copyright 1991 Wayne E. McDaniel, All rights reserved. Printed
in the United States of America.
The AutoLibrary(tm) Program-Playback tool Shareware diskette,
which contains a copy of this manual, may be freely copied and
shared.
However, multiple copies of this document may not be printed and
printed copies of this document may not be copied in any way
without permission in writing from Avid Software.
Table of Contents
Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4
Installation . . . . . . . . . . . . . . . . . . . . . . . . 8
System Requirements . . . . . . . . . . . . . . . . . . . . . 9
Optional Requirements . . . . . . . . . . . . . . . . . . . . 9
Discussion of Requirements . . . . . . . . . . . . . . . . . 9
Compiling Source . . . . . . . . . . . . . . . . . . . . . . 9
Compiling Interface Libraries . . . . . . . . . . . . . . . . 9
Compiling Applications . . . . . . . . . . . . . . . . . . . 10
Getting Started Using Example 1 (ex01.exe) . . . . . . . . . 11
Getting Started Using Example 2 (ex02.exe) . . . . . . . . . 14
A Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . 15
Reference Guide For the AutoLibrary(tm) Program-Playback
tool . . . . . . . . . . . . . . . . . . . . . . . . . . 33
AvidClosePort - Close Communication Port . . . . . . . . 34
AvidConvert - Convert Characters to Strings . . . . . . 36
AvidDrainPort - Drain Communication Port . . . . . . . . 38
AvidExitAutoLibrary - Exit AutoLibrary . . . . . . . . . 41
AvidGetFromHoldArea - Get Characters from Hold Area . . 43
AvidInitAutoLibrary - Initialize AutoLibrary . . . . . . 45
AvidLogInfo - Log information to file or screen. . . . . 47
AvidLogOpen - Open a Log File. . . . . . . . . . . . . . 51
AvidOpenPort - Open Communication Port . . . . . . . . . 53
AvidProcessOptions - Parse an Option Parameter List . . 57
AvidRead - Read a Character . . . . . . . . . . . . . . 60
AvidRegisterSend - Register a String to Send . . . . . . 63
AvidRegisterWait - Register a Wait String . . . . . . . 65
AvidSend - Send a String . . . . . . . . . . . . . . . . 67
AvidSendSearch - Send Strings then Search . . . . . . . 69
AvidVersion - Print Version and Copyright Information . 76
EveryChar - Called with Every Character Received . . . . 77
Reference Guide for Interface Routines . . . . . . . . . . . 79
CommInterfaceClose - Close port . . . . . . . . . . . . 80
CommInterfaceOpen - Open Port . . . . . . . . . . . . . 82
CommInterfaceRead - Read Character . . . . . . . . . . . 94
CommInterfaceSend - Send Character . . . . . . . . . . . 105
4
Introduction
The AutoLibrary(tm) Program-Playback tool is a C function library
for automation. Automation is coded into programs then played
back when the program executes.
This tool will not replace any of your existing automation tools.
You will still use your terminal emulator's script language for
automatic access to bulletin boards and online services and you
may still want your Capture-Playback tool to create quick and
convenient regression tests.
Instead of replacing any tool, add this tool to your personal
tool box and use it when it offers the best solution.
To determine if this tool offers you the best solution, consider
the following questions.
1. Is there a serial connection to the system being
automated? Or can there be by redirecting I/O or
designing in a serial test port?
2. Are you automating with ASCII characters?
3. Do you want C as your programming language, where
automation is hand coded into subroutines?
If your answers to the previous questions were yes, you will
need...
1. A PC with a serial port.
2. Turbo C version 2.0
Or you will need to do one or more of the following...
1. Port this to a different operating system.
2. Port the interface routines to something other than RS-
232.
3. Port the interface routines to a different
communications package.
4. Port to a different C compiler.
The features of this tool combined with the C programming
language, give you the benefit of writing easy and flexible
5
automation programs. The following list shows some of the
features and benefits you will like.
1. Your automation programs can be distributed without
script files or interpreters.
2. Your automation programs will take advantage of the C
programming language for many things like: file I/O,
flow control, variable declarations, parameterized
subroutines, and so on. Also, you can take advantage
of C debuggers, profilers, linkers, and other add-on
libraries. You will be able to create generic
automation libraries using the C librarian for
distribution to other members of your group.
3. Your automation programs will not have to depend on
play back timing or comparisons to previous runs.
Instead, your automation programs will have the
expected results coded in.
4. Your automation programs will take advantage of the way
this tool handles timeouts.
There are two types of timeouts: Repeating-Timeouts and
Ending-Timeouts. Repeating timeouts start over after
each newly received character and ending timeouts
don't.
5. Your automation programs will handle variations of
play-back input by registering multiple strings to wait
for.
6. Your automation programs will take advantage of the
options parameter each routine has. This parameter
allows customized use of the routines. It will also
allow me to add functionality without adding new
interfaces or changes existing ones.
7. Your automation programs may take advantage of the
EveryChar routine. This routine is written by you and
is called with each received character.
8. Your automation programs may take advantage of your
ability to vary the send delay between each character
sent.
6
The following lists each of the routines in this tool...
The main routines that support automation sequences...
AvidRegisterSend - Register a string to send.
AvidRegisterWait - Register a wait string.
AvidSendSearch - Send strings then search.
The others in alphabetical order...
AvidClosePort - Close communication port.
AvidConvert - Convert characters to strings.
AvidDrainPort - Drain communications port.
AvidExitAutoLibrary - Exit AutoLibrary.
AvidGetFromHoldArea - Get characters from hold area.
AvidInitAutoLibrary - Initialize AutoLibrary.
AvidLogInfo - Log information to file or screen.
AvidLogOpen - Open a log file.
AvidOpenPort - Open communication port.
AvidProcessOptions - Parse an option parameter list.
AvidRead - Read a character.
AvidSend - Send a string.
AvidVersion - Print version and copyright information.
EveryChar - Called with every character received.
Interface routines to your communications library...
CommInterfaceClose - Close port.
CommInterfaceOpen - Open port.
CommInterfaceRead - Read Character.
CommInterfaceSend - Send Character.
7
The following list shows some of the applications this tool would
be good for. (The items with an asterisk are projects that I
have done using this automation technique.)
- Automating CompuServe access.
- Controlling/testing a modem.
- Controlling/testing an ASCII Terminal
- Controlling/testing Unix or a program running on Unix.
- Controlling/testing other mini or mainframe computer
systems.
- Controlling/testing Bulletin Board Systems
- Controlling/testing Data Switches.
- * Network monitoring from users perspective.
- Controlling/testing Special equipment. For example,
medical instruments. Especially instruments that have
serial ports designed in to help support automated
testing.
- * Controlling/testing Target debug monitors.
- Controlling/testing Prom programmers.
- Controlling/testing anything that has a serial
connection or can be redirected through a serial
connection.
8
Installation
For installation instructions see the readme file for installing
this software.
Please see the PACKAGE.LST file for a description of CONSULT.DOC,
SUPPORT.DOC, LICENSE.DOC, and so on. Within these files are
important information about registering, warranty, support,
license agreements, vendor/sysop information, hiring me as a
contractor/consultant, and so on.
9
System Requirements
a) Turbo C v2.0
b) COM 1 or COM 2
c) IBM PC or compatible
Optional Requirements
a) A communication package, such as, Greenleaf Comm Library
v2.21 (Should work with v3.0)
Discussion of Requirements
The AutoLibrary Program-Playback Tool communicates via interface
routines to the communication package. I provide a basic
asynchronous RS-232 communication package with this tool to get
you started. However, I recommend using a communication package
with additional features and a proven track record.
Interface routines are provided for the Greenleaf Comm Library.
However, you may port the interface routines to any one of the
many communication packages. This manual contains detailed
instructions for doing this.
It is possible for both registered and unregistered users to
write interface routines for a different communication package.
Also, given registered user receive the source, it is possible to
port this tool to other compilers and operating systems.
Compiling Source
The source code is generated by the batch file genauto.bat. Make
sure Turbo C is located in \tc or edit the batch files with your
Turbo C path.
Compiling Interface Libraries
The interface libraries are generated by the batch file
genface.bat. Make sure Turbo C is located in \tc and the
Greenleaf Comm Library is located in \gls or edit the batch files
with your pathnames.
10
Please see the detailed information on how to port the interface
routines to use other communication packages. The information is
documented in the reference section for CommInterfaceClose,
CommInterfaceOpen, CommInterfaceRead, and CommInterfaceSend.
Compiling Applications
To compile your application, I recommend starting with example
one in the self-extracting file ex01.exe. Copy this file to a
clean directory, then execute ex01. Here you will find a
template file ready to compile with genex01.bat.
11
Getting Started Using Example 1 (ex01.exe)
The goal of this section is to provide you with a simple example
to get you started. Also, to help you get started, read the
tutorial section. This will give you an overview of how to
automate using the AutoLibrary(tm) Program-Playback tool. You
may run the Wyse demo if it is convenient, i.e., if you have a
Wyse terminal handy. Regardless of whether you are able to run
the Wyse demo, I recommend doing a quick code review of the demo.
Start with example 1 and then look at example 2. The examples
are in self-extracting files ex01.exe and ex02.exe. Execute
these programs in clean directories to extract the files.
When getting started with something new, it is nice to know the
minimum that is required. Therefore, I have supplied a template
file (template.c from ex01.exe) that contains the minimum
required for the AutoLibrary(tm) Program-Playback tool. The
following code is a listing of template.c.
12
/* template.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "al.h"
/*****/
void EveryChar(c)
int c;
/*****/
{
/* Print each character received. */
printf("%c", c);
}
/*****/
void main(argc, argv)
/*****/
int argc;
char *argv[];
{
int com;
int err, add_info;
argc = argc; /* for compiler. */
argv = argv; /* for compiler. */
/* Initial AutoLibrary. */
AvidInitAutoLibrary(AVID, &add_info, "_B'3'");
/* Open the communication port. */
com = AvidOpenPort(AVID, "com1", &add_info,
".b'9600' .1 .8 .n +S -H");
/* Display AutoLibrary version. */
AvidVersion(AVID, &add_info, "");
/* Ready for automation. */
/* Finished so close the com port. */
AvidClosePort(AVID, com, &add_info, "");
/* Exit from AutoLibrary. */
AvidExitAutoLibrary(AVID, &add_info, "");
}
13
The above template program has been supplied with this product
and can be compiled. If the following automation sequence was
added to the template file, it would send "Hello World" to
whatever the PC was connected to. Then it would wait for the
string "Hello Back".
AvidRegisterSend(AVID, com, "Hello World", &add_info, "");
AvidRegisterWait(AVID, com, 1, "Hello Back", &add_info, "");
if ((AvidSendSearch(AVID, com,(long)20, (long)120,
&add_info, "")) == 1)
printf("Found Hello Back.\n");
else
printf("Timeout occurred.\n");
If you add this code and connect your PC to a terminal or a PC
running terminal emulation software, you will see the "Hello
World" string printed. Then, from the terminal or PC running
terminal emulation software, you can type in the string "Hello
Back", which would result in a successful automation sequence.
This example is small, but it gives you a feel for how automation
works. A command string is sent out, then one or more strings
are scanned for.
Note that this example is a bit odd. Normally, automation
programs are connected to programs or equipment that can
communicate on there own. For this example, you simulated
something being automated when you typed in "Hello Back".
14
Getting Started Using Example 2 (ex02.exe)
To run the wyse terminal demo you will need to connect
communication port one (com1) of a PC to a Wyse 30, Wyse 50, or
Wyse 60. For a Wyse 60 terminal, invoke the setup and select the
Wyse 50 compatibility mode. When connecting the PC to the
terminal, a null modem may be required.
The wyse terminal demo is executed from a command line interface
that works much like a Unix utility. The code in wyse1.c is the
program control code, where as, the code in wyse.c is the
automation routines.
By typing in 'wyse' (without options), a help screen is
displayed. For example...
C:\EX02\>wyse
Usage: wyse <options>
Where: <options> are...
+a --- Run all tests.
.A --- Abort program if an error occurs. (Default is continue)
-L --- Run long version of tests.
+p --- Run protected mode test.
-a --- Run screen attributes test.
+s --- Run screen location test.
+P --- Run screen print test.
The following will run all of the tests and abort if there is an
error.
C:\EX02\>wyse +a .A
The following will run the Screen Attributes test and the
Protected Mode test. The long versions of these tests will be
run if they exist.
C:\EX02\>wyse -a +p -L
One of the tests has been coded to purposely report errors. This
will demonstrate what error messages look like.
15
A Tutorial
The goal of this tutorial is to introduce you to automation using
the AutoLibrary(tm) Program-Playback tool.
This tutorial uses a PC and a Wyse 50 terminal. The serial
connection between the PC and the Wyse 50 terminal places the PC
in the unusual role of "host computer." On the other hand,
everything seems normal to the terminal, which displays
characters when received and sends characters when typed in. The
Wyse 50 does not know it is connected to a PC.
Once the PC and Wyse 50 are connected, we can write automation
routines that send and receive from the terminal. This tutorial
focuses on a Wyse 50 command that allows host computers to
identify the terminal. The command has the format "ESC<space>",
and is one of many Wyse 50 escape codes. When the Wyse 50
receives this command, it returns the string "50\r". The '\r'
character is the C notation for a return character. The
following code segment is the first of many that will use the
"ESC<space>" escape command to illustrate automation techniques
using the AutoLibrary(tm) Program-Playback tool.
sprintf(temp_s, "%s ", ESC_CODE);
AvidRegisterSend(AVID, com, temp_s, &add_info, "");
AvidRegisterWait(AVID, com, 1, "50", &add_info, "");
register_value = AvidSendSearch(AVID,
com,(long)5, (long)10, &add_info, "");
The calls to AvidRegisterSend and AvidRegisterWait result in two
linked lists being built for AvidSendSearch: the send-list and
the wait-list. The call to AvidRegisterSend does not actually
send the string. Instead, AvidSendSearch sends all of the
strings in the send-list and then begins a search for the strings
in the wait-list.
In this example, AvidSendSearch sends the command "ESC<space>" to
the Wyse 50 terminal, then begins a search for the string "50".
The value returned depends on the outcome of the search. If the
string "50" is found, the return value will be 1. If the string
"50" is not found, the value 0 will be returned. Zero is always
returned when none of the strings in the wait-list are found.
Notice, when the string is found, the returned value depends on
what was registered. In this example, the string "50" was
registered with 1. It could have been registered with the value
527, which would cause AvidSendSearch to return 527 when the
string was found.
16
It is possible to register more than one string in the send-
list. However, this is not done very often, since complicated
send strings can be built using 'sprintf'. It is different for
the wait-list. Your programs will have multiple wait strings
many times. Since the Wyse 30, Wyse 50, and Wyse 60 have
compatibility modes, it makes sense to write the above sample
code segment as follows.
sprintf(temp_s, "%s ", ESC_CODE);
AvidRegisterSend(AVID, com, temp_s, &add_info, "");
AvidRegisterWait(AVID, com, 1, "30", &add_info, "");
AvidRegisterWait(AVID, com, 2, "50", &add_info, "");
AvidRegisterWait(AVID, com, 3, "60", &add_info, "");
register_value = AvidSendSearch(AVID, com,
(long)5, (long)10, &add_info, "");
Nothing is different except for the two additional calls to
AvidRegisterWait. These calls allow AvidSendSearch to search for
the strings "30", "50", and "60" at the same time.
AvidSendSearch will return 1 if connected to a Wyse 30, 2 if
connected to a Wyse 50, and 3 for a Wyse 60. ERR_SNF (Zero) is
returned if none of these terminals are connected.
Now, suppose the PC's serial port is disconnected. Given the
above code segment, AvidSendSearch will timeout and return
ERR_SNF (String-Not-Found).
The AutoLibrary(tm) Program-Playback tool supports two types of
timeouts: A Repeating Timeout and an Ending Timeout. Before
defining repeating and ending timeouts, notice that the basic
model of automation requires timeouts. Automation is
programmatically sending a keystroke sequence, then scanning the
output for a list of expected responses. When none of the
expected responses are found, a timeout must occur. The program
will enter an endless loop without a timeout feature.
A repeating timeout starts over after each received character.
Therefore, if a repeating timeout of 10 seconds is specified, the
timeout will not occur unless there is communication silents for
10 seconds. A timeout will never occur if characters are
continuously received. An ending timeout, on the other hand, is
not reset with each newly received character. If an ending
timeout of 20 seconds is specified, a timeout will occur in 20
seconds regardless, assuming none of the expected responses are
received.
17
These two types of timeouts can play an important role in writing
correct automation "scripts." The repeating timeout can be given
a reasonable timeout value and still be able to handle many
variations in input. The ending timeout can be given a large
value, which could indicate an error condition. When
AvidSendSearch returns ERR_SNF due to a timeout, the return
parameter 'add_info' will be set to ERR_ENDING_TIMEOUT or
ERR_REPEAT_TIMEOUT.
A topic that is related to timeouts is draining communication
ports. Draining a communication port is simply reading in
characters while ignoring them for a specified amount of time.
The time period to drain a communication port can be a Repeating
Drain and an Ending Drain. A repeating drain starts over with
each newly received character. There needs to be communication
silents for repeating drains to stop. An ending drain will stop
after the specified amount of time regardless of communication
activity.
The following is the same sample code segment with the additional
call to AvidDrainPort.
sprintf(temp_s, "%s ", ESC_CODE);
AvidRegisterSend(AVID, com, temp_s, &add_info, "");
AvidRegisterWait(AVID, com, 1, "30", &add_info, "");
AvidRegisterWait(AVID, com, 2, "50", &add_info, "");
AvidRegisterWait(AVID, com, 3, "60", &add_info, "");
register_value = AvidSendSearch(AVID, com,
(long)5, (long)10, &add_info, "");
AvidDrainPort(AVID, com, (long)1, (long)3, &add_info, "");
This drains the communication port of the <cr> character.
Remember that when a Wyse 50 terminal receives the "ESC<space>"
command, it returns "50<cr>". However, the wait-list contains
only the string "50", which causes the <cr> character not to be
read in. To guard against the <cr> character effecting the next
automation sequence, it is drained.
Another way to make sure the <cr> is read in, is to include it in
the wait string. The following example demonstrates this.
sprintf(temp_s, "%s ", ESC_CODE);
AvidRegisterSend(AVID, com, temp_s, &add_info, "");
AvidRegisterWait(AVID, com, 1, "30\r", &add_info, "");
AvidRegisterWait(AVID, com, 2, "50\r", &add_info, "");
18
AvidRegisterWait(AVID, com, 3, "60\r", &add_info, "");
register_value = AvidSendSearch(AVID, com,
(long)5, (long)10, &add_info, "");
You will notice the call to AvidDrainPort is gone and the '\r'
character has been added to the wait strings. For this example,
adding the '\r' character is better than calling AvidDrainPort,
only because the one second delay in AvidDrainPort is avoided.
The two methods, otherwise, result in the same thing.
In general, draining is needed when there are leftover characters
after an automation sequence has finished. In the above example,
the '\r' was a leftover character. You will find draining
communication ports very useful when the leftover characters of
an automation sequence varies.
The following code segment will be familiar by now. It sends the
"ESC<space>" command to the Wyse 50 terminal then scans for the
string "50". When finished, the '\r' character is drained.
sprintf(temp_s, "%s ", ESC_CODE);
AvidRegisterSend(AVID, com, temp_s, &add_info, "");
AvidRegisterWait(AVID, com, 1, "50", &add_info, "");
register_value = AvidSendSearch(AVID, com,
(long)5, (long)10, &add_info, "");
AvidDrainPort(AVID, com, (long)1, (long)3, &add_info, "");
The following code segment works the same way as above, but uses
switches instead.
sprintf(temp_s, ".s'%s ' 1w'50' .d'1'", ESC_CODE);
value = AvidSendSearch(AVID, com, (long)5, (long)10,
&add_info, temp_s);
With switches, the same automation sequence can be accomplished
with one call to AvidSendSearch. The .s'%s ' switch adds the
"ESC<space>" string to the send-list, the 1w'50' switch adds the
string "50" to the wait-list, and the switch .d'1' indicates
there is to be a drain after the automation sequence has
finished. These switches replace the need to call
AvidRegisterSend, AvidRegisterWait, and AvidDrainPort explicitly.
Here is the same call again with two additional wait strings.
19
sprintf(temp_s, ".s'%s ' 7w'30' 6w'50' 9w'60' .d'1'", ESC_CODE);
value = AvidSendSearch(AVID, com, (long)5, (long)10,
&add_info, temp_s);
In this example, AvidSendSearch will send the "ESC<space>"
command then search for the strings "30", "50", and "60". If the
string "30" is found, AvidSendSearch returns 7, if "50" is found,
6 is returned and if "60" is found, 9 will be returned.
Notice that the switch .D'3' would also be required to make the
switched version match the unswitched version exactly. The .d'1'
switch causes a Repeating Drain for one second and the .D'3'
would cause a 3 second Ending Drain.
The "ESC<space>" command would make a nice general purpose
routine that other parts of the automation program could call.
Here is a boolean function that returns TRUE if a Wyse 30, 50, or
60 is connected and FALSE if not.
/****************/
int wyse_terminal(com)
int com;
/****************/
{
char temp_s[85];
int err;
int add_info;
/*
Test to see if connected to a Wyse terminal.
Use the command ESC<space>
Where:
<space> is a blank space.
The Wyse terminal will return 30\r, 50\r, or 60\r
*/
sprintf(temp_s, ".s'%s ' 1w'30' 2w'50' 3w'60' .d'1'",
ESC_CODE);
if ((err = AvidSendSearch(AVID, com, (long)1, (long)3,
&add_info, temp_s)) <= ERR_SNF)
return(FALSE);
else
return(TRUE);
}
Since all error codes are returned as negative numbers, the test
for less than or equal to ERR_SNF will work fine. This just
20
means that FALSE will be returned if none of the strings in the
wait-list are found or an error is returned by AvidSendSearch.
TRUE will be returned if AvidSendSearch returns 1, 2, or 3.
Other parts of the program would then be able to make calls like
the following.
/* Before testing begins, make sure we are cable correctly. */
if ( !wyse_terminal(com)) {
AvidLogInfo(AVID, com, "Bad connection to Wyse terminal",
BAD_CONNECTION, &add_info, "");
}
Since the automation routine 'wyse_terminal' is of general use,
it could be put in a function library with other automation
routines written for wyse terminals. The library could then be
distributed to other members of the programming staff. Creating
general use automation routines allows automation programs to be
written like regular programs using a modular design.
The following routine is an improvement on the 'wyse_terminal'
routine. It will return a constant that specifies the type of
wyse that is connected.
21
/****************/
int terminal_type(com)
int com;
/****************/
{
char temp_s[85];
int err;
int add_info;
/*
Test to see if connected to a Wyse terminal.
Use the command ESC<space>
Where:
<space> is a blank space.
The Wyse terminal will return 30\r, 50\r, or 60\r
*/
sprintf(temp_s, "%s ", ESC_CODE);
AvidRegisterSend(AVID, com, temp_s, &add_info, "");
AvidRegisterWait(AVID, com, WYSE_30, "30", &add_info, "");
AvidRegisterWait(AVID, com, WYSE_50, "50", &add_info, "");
AvidRegisterWait(AVID, com, WYSE_60, "60", &add_info, "");
return(AvidSendSearch(AVID, com, (long)2, (long)5,
&add_info, ".d'1'.D'3'"));
}
Other parts of the program would then be able to make calls like
the following.
/* Before testing Wyse 50 features, make sure this is a Wyse 50.
*/
if ( terminal_type(com) != WYSE_50)
return;
Notice that the 'terminal_type' routine uses AvidRegisterSend and
AvidRegisterWait to build the send-list and wait-list. This is a
nice way to code this routine because of the constants WYSE_30,
WYSE_50, and WYSE_60. These constants would be defined in a
global header file and can be given any valid values. If
switches were used like in previous examples, WYSE_30 would have
to be defined as 1, WYSE_50 as 2, and WYSE_60 as 3. It is best
that the 'terminal_type' routine not be required to match the
constant definitions.
22
The call to AvidSendSearch uses the .d'1' and .D'3' switches to
drain the communication port. An explicit call to AvidDrainPort
would have yielded the same result.
The above implementation of 'terminal_type' is a very good way to
code this automation routine. However, I would like to code it a
different way to demonstrate AvidSendSearch's ability to capture
strings. By adding the switch -c'2' and the parameters 'actual'
and 'captured' to AvidSendSearch, a string capture is possible,
as the following code segment will show.
/****************/
int terminal_type(com)
int com;
/****************/
{
char temp_s[85];
int err, add_info;
char captured[50];
long actual;
/*
Test to see if connected to a Wyse terminal.
Use the command ESC<space>
Where:
<space> is a blank space.
The Wyse terminal will return 30\r, 50\r, or 60\r
*/
sprintf(temp_s, ".s'%s ' 1w'\r' .d'1' .D'3' -c'2'",
ESC_CODE);
if ((err = AvidSendSearch(AVID, com,
(long)2, (long)5, &add_info, temp_s,
(long *)&actual, captured)) <= ERR_SNF)
return(err);
return(atoi(captured));
}
The -c'2' switch causes two characters to be captured. After the
Wyse 50 receives the "ESC<space>" command, it returns 3
characters. First, the character is '5', then '0', and then the
return character '\r'. The capture string starts out empty, then
fills up during the automation sequence. The following list
shows how the capture string fills.
23
"" - String empty.
"5" - First character received.
"50" - Next character received.
"50" - The return character received.
When the return character is received, the automation sequence
stops. Notice that the wait string ("\r" here) is not part of
the captured string.
Suppose the Wyse 50 responds to the "ESC<space>" command
differently. Instead of "50\r", say the Wyse 50 terminal
returned "Wyse50\r". The code above will still work by capturing
only the string "50". However, the capture string will fill up
differently as shown below.
"" - String empty.
"W" - First character received.
"Wy" - Next character received.
"ys" - Next one.
"se" - Next one.
"e5" - Next one.
"50" - Next one.
"50" - The return character received.
This illustrates how the capture will start ignoring characters
by letting them drop off of the end.
The actual number of characters in the capture string may be less
than the amount specified in the switch. This happens when the
automation sequence ends before the capture string is filled.
Also, since NULL characters can be part of the input stream, the
actual number of characters in the captured string is passed back
to you in the parameter 'actual'. Strlen(captured) may not equal
the actual number of characters in the captured string due the
NULL characters.
There are actually two types of string captures possible from
AvidSendSearch. The above sample code demonstrated the first
type, which is initiated with the switch -c'x', where x is the
maximum number of characters to capture. The second type of
capture is invoked with the +c'x' switch, where x, again, is the
number of characters to capture. However, there is a big
difference between these two types of captures. The first type
(-c'x') starts pushing the oldest characters out of the capture
string after x characters have been received. The second type of
capture (+c'x'), on the other hand, stops the automation sequence
when the capture string is full.
24
Before demonstrating the +c'x' capture, a little history. When I
first wrote the AutoLibrary(tm) Program-Playback tool,
AvidSendSearch did not support capturing strings. Instead, the
only way to get captured strings were to extract them from a hold
area with the routine AvidGetFromHoldArea. Using
AvidGetFromHoldArea is still a valid way to get capture strings,
which the following code segment will show. You will notice this
code segment gives the same results as the code segment above
that uses the -c'2' switch.
/****************/
int terminal_type(com)
int com;
/****************/
{
char temp_s[85];
int err, add_info;
char captured[50];
long actual;
/*
Test to see if connected to a Wyse terminal.
Use the command ESC<space>
Where:
<space> is a blank space.
The Wyse terminal will return 30\r, 50\r, or 60\r
*/
sprintf(temp_s, ".s'%s ' 1w'\r' .d'1' .D'3'", ESC_CODE);
if ((err = AvidSendSearch(AVID, com, (long)2, (long)5,
&add_info, temp_s)) <= ERR_SNF)
return(err);
actual = AvidGetFromHoldArea(AVID, com, 1, 2,
captured, &add_info, "");
return(atoi(captured));
}
You will find AvidGetFromHoldArea useful in your automation
routines because of its ability to extract from anywhere in the
hold area and be able to span across data that was received from
multiple automation sequences. AvidGetFromHoldArea is a general
utility for extracting capture strings. However, I found that
for the vast majority of strings that I wanted to capture,
convenience was more important. Therefore, I added the capture
switch to AvidSendSearch. Internally, AvidSendSearch calls
AvidGetFromHoldArea with the correct parameters. This process of
25
capturing strings seemed very natural to me. The process where
AvidSendSearch does not worry about the capture string until the
automation sequence is over. Then it looks backwards into the
hold area to extract out the capture string. This method of
looking backwards into the hold area led naturally to the second
type of capture. Namely, a forward looking capture. One that
would start putting characters into the capture string as they
were received from the communication port. One where
AvidSendSearch worries about the capture string before the
automation sequence starts.
The forward looking capture is invoked with the switch +c'x'.
This type of capture will be referred to as a Positive Capture.
The backward looking capture is invoked with the switch -c'x' and
is referred to as a Negative Capture. Just remember the minus
sign '-' as the Negative Capture and the plus character '+' as
the Positive Capture. Also, remember that the Negative Capture
looks backwards into the hold area after the automation sequence
has finished. Where as, the Positive Capture looks forward and
builds the capture string as the automation sequence is
occurring. The Positive Capture will terminate the automation
sequence if the capture string is full. The Negative Capture
will never end the automation sequence.
It is useful to again code the Wyse 50's host identification
command "ESC<space>" using a Positive Capture.
26
/****************/
int terminal_type(com)
int com;
/****************/
{
char temp_s[85];
int err, add_info;
char captured[50];
long actual;
/*
Test to see if connected to a Wyse terminal.
Use the command ESC<space>
Where:
<space> is a blank space.
The Wyse terminal will return 30\r, 50\r, or 60\r
*/
sprintf(temp_s, ".s'%s ' .d'1' .D'3' +c'2'", ESC_CODE);
if ((err = AvidSendSearch(AVID, com,
(long)2, (long)5, &add_info, temp_s,
(long *)&actual, captured)) <= ERR_SNF)
return(err);
return(atoi(captured));
}
The +c'2' switch specifies a Positive Capture of two characters.
The following list shows how the capture string is filled.
"" - String empty.
"5" - First character received.
"50" - Next one.
"50" - The automation sequence ends because the
capture string is full.
- The drain switches .d'1' and .D'3' will
drain the '\r' character.
Suppose, as we did with the Negative Capture, that the Wyse 50
returned "Wyse50\r" instead of "50\r". Remember the examples
showed the resulting capture string was "50" regardless of
whether the Wyse 50 returned "Wyse50\r" or "50\r". The result is
different, however, for Positive Captures, as the following list
will show.
27
"" - String empty.
"W" - First character received.
"Wy" - Next character received.
"Wy" - The automation sequence ends with this as
the capture string. - The drain switches then
drain the characters "se50\r" (Not what is
desired).
As you can see the result is not what was desired. However,
since we know the Wyse 50 really will return "50\r", both capture
methods work fine.
Again, suppose the Wyse 50 worked yet another way, where say, all
terminal made before 1983 returned "Wyse50\r" and all terminals
made after 1983 returned "50\r". To make our automation routine
work with both types of Wyse 50 terminals, the routine that uses
the Negative Capture would be the only correct solution.
I would like to describe the Positive Capture again with a better
suited example. The previous examples were good, however, they
compared the Positive Capture with the Negative Capture in a
situation where the Negative Capture was the best choice. Now I
would like to describe an example that is better suited for a
Positive Capture.
One place where the Positive Capture is best suited, is when the
string to key off of is before the information to be captured.
Before describing a new example, the Reference Manual does have a
good example for Positive Captures, which captures information
about the current whether conditions. In this example, the
string "Temperature" is always displayed before the current
temperature. First, a call is made to AvidSendSearch that waits
for the string "Temperature", then another AvidSendSearch call is
made to actually capture the temperature. A complete description
of this example can be found in the reference guide in the
section that describes AvidSendSearch.
Another place where the Positive Capture is best suited is when
the number of characters to capture needs to have an upper limit.
The following code captures the next 80 characters of an input
stream.
AvidSendSearch(AVID, com,
(long)10, (long)60, &add_info,
"+c'80' 1w'\r' 2w'\n'", (long *)&actual, captured);
This piece of code would be used for reading in a "line" of data
much like a line of data would be read from a file. When 80
characters have been received, AvidSendSearch will return with
28
the 80 characters in the capture string and the automation
sequence would be finished. If, however, a newline character
('\n') or a return character ('\r') is received, AvidSendSearch
would return with less than 80 characters in the capture string.
Notice there were no send strings. It is ok (and common) for
AvidSendSearch to be called without a send string. For
instances, a previous call to AvidSendSearch may have already
started an input stream. It is also possible, depending on the
type of application or device that is being automated, that an
input stream does not need initiated, i.e., characters will be
coming in as soon as the port is opened.
The following code segment adds to the previous one. Here,
AvidSendSearch is put in a while loop. AvidSend is used to send
the command that starts the data flowing.
AvidSend(AVID, com, "facts\r", &add_info, "");
while (( err = AvidSendSearch(AVID, com,
(long)10, (long)60, &add_info,
"+c'80' 1w'\r' 2w'\n'",
(long *)&actual, captured)) >= ERR_SNF) {
/* It is ok for err to equal ERR_SNF if caused by capture
string filling up. */
if ((err == ERR_SNF) && (add_info != ERR_CAPTURE_FULL))
break;
/* Write captured string to a file. */
fprintf(cap_file, "%s\n", captured);
}
Notice that AvidSend was used to send the command 'facts' to the
host computer. AvidSendSearch could have been used, with
"facts\r" registered in the send-list and nothing registered in
the wait-list. However, AvidSend is a better choice here.
AvidSendSearch would have been a better choice if any of the
other AvidSendSearch features were needed, such as, draining the
communication port.
This is the first example that uses 'add_info'. 'Add_info' is a
return parameter that allows your automation programs to get more
information on why an error occurred. This example needs to know
why the ERR_SNF was returned. If ERR_SNF was returned due to a
timeout, 'add_info' will return with ERR_REPEAT_TIMEOUT or
ERR_ENDING_TIMEOUT.
29
Notice the above example compares 'add_info' to ERR_CAPTURE_FULL.
This is the best way to find out if the automation sequence
should continue. When ERR_SNF is returned due to the capture
string being full, more characters are out there to capture.
Now to summarize what we have looked at so far. This tutorial
has introduced you to the following routines.
AvidDrainPort --- Drains a communication port.
AvidGetFromHoldArea --- Gets a string from the hold area.
AvidLogInfo --- Log messages to a log file.
AvidRegisterSend --- Registers a string in the send-list.
AvidRegisterWait --- Registers a string in the wait-list.
AvidSend --- Sends a string.
Here is a list of the routines that I would like to introduce
now.
AvidClosePort --- Closes an AutoLibrary port.
AvidExitAutoLibrary --- Exit from AutoLibrary.
AvidInitAutoLibrary --- Initializes AutoLibrary.
AvidOpenPort --- Opens an AutoLibrary port.
AvidVersion --- Displays the AutoLibrary version.
The following example uses these routines to put it all together.
The example will call the routine 'terminal_type' to determine
the type of terminal connected. It will then print the answer to
the screen.
30
#include <stdio.h>
#include <stdlib.h>
#include "al.h"
/******/
void main(argc, argv)
/******/
int argc;
char *argv[];
{
int com;
int add_info;
/* Initial AutoLibrary. */
AvidInitAutoLibrary(AVID, &add_info, "_B'3'");
/* Open the communication port. */
com = AvidOpenPort(AVID, "com1", &add_info,
".b'9600' .1 .8 .n +S -H");
/* Display AutoLibrary version. */
AvidVersion(AVID, &add_info, "");
/* Display the type of Wyse Terminal that is out there. */
if ((term_type = terminal_type(com)) = 0)
printf("Not connected to a Wyse 30, 50, or 60\n");
else
printf("Connected to a Wyse %i terminal\n", term_type);
/* Finished so close the com port. */
AvidClosePort(AVID, com, &add_info, "");
/* Finished so exit from AutoLibrary. */
AvidExitAutoLibrary(AVID, &add_info, "");
}
31
/****************/
int terminal_type(com)
int com;
/****************/
{
char temp_s[85];
int err, add_info;
char captured[50];
long actual;
/*
Test to see if connected to a Wyse terminal.
Use the command ESC<space>
Where:
<space> is a blank space.
The Wyse terminal will return 30\r, 50\r, or 60\r
*/
sprintf(temp_s, ".s'%s ' 1w'\r' .d'1' .D'3' -c'2'",
ESC_CODE);
if ((err = AvidSendSearch(AVID, com,
(long)2, (long)5, &add_info, temp_s,
(long *)&actual, captured)) <= ERR_SNF)
return(err);
return(atoi(captured));
}
Now all of the routines in the AutoLibrary(tm) Program-Playback
tool have been introduced in this tutorial except for the
following.
AvidConvert --- Utility routine that converts characters to
strings.
AvidLogOpen --- Open a log file for AvidLogInfo to use.
AvidProcessOptions --- Used to process the options
parameter.
AvidRead --- Reads one character.
AvidConvert and AvidProcessOptions are utility routines that your
automation programs may use. AvidConvert converts characters
into strings. When a character is not printable, AvidConvert
will change it to a printable string. AvidProcessOptions is the
routine that is used internally to process the option parameter.
Your programs can use this routine if you also want to support an
32
options parameter. AvidLogOpen opens a log file for AvidLogInfo
to use.
AvidRead is used internally by AvidDrainPort and AvidSendSearch.
Your automation programs should not require this routine. It was
included only for completeness. The Reference Guide has a more
information on these routines.
This concludes the tutorial of the AutoLibrary(tm) Program-
Playback tool. I hope this section has given you a feel for how
automation is done using this tool.
33
Reference Guide For the AutoLibrary(tm) Program-Playback tool
The following is the reference guide for the AutoLibrary(tm)
Program-Playback tool. Each routine is described along with its
parameters and options. Examples are supplied for each routine.
34
AvidClosePort - Close Communication Port
err = AvidClosePort(AVID, com, (int *)&add_info, opts)
Parameter Description
int err; -- Return code.
AVID -- System parameter that must always be specified.
int com; -- The communications port to close.
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
Options
NONE
Return Codes
ERR_OK -- No error occurred.
ERR_NOT_INITIALIZED -- This error is returned when
AvidInitAutoLibrary is not called before this
routine is called.
ERR_COMM_PACKAGE -- This error can occur when the
communication package cannot close the
communication port correctly. When this
error occurs, the parameter 'add_info' will
contain the actual error returned by the
communication package.
ERR_INVALID_PORT -- This error can occur when the
communication port specified in the 'com'
parameter was not a valid opened port.
Additional Information Return Codes
ERR_OK -- No error occurred.
<system err> -- When ERR_COMM_PACKAGE is returned, 'add_info'
contains the actual error returned by the
communication package.
AvidClosePort
35
Description
This routine closes the communication port that was opened by
AvidOpenPort. All of the memory allocated by AvidOpenPort is
freed. This routine calls CommInterfaceClose so the
communication port of the comm package can be closed. This
routine will close the log if one was opened by AvidLogOpen.
Examples
The following example assumes there will not be any problems
closing the port.
AvidClosePort(AVID, com, &add_info, "");
The following example checks for problems when closing the port.
if ((err = AvidClosePort(AVID, com, &add_info, "")) != ERR_OK)
printf("Error = %d, Additional Info = %d\n", err, add_info);
See Also
AvidOpenPort, CommInterfaceClose
AvidClosePort
36
AvidConvert - Convert Characters to Strings
err = AvidConvert(c, s, (int *)&add_info, opts)
Parameter Description
int err; -- Return code.
int c; -- Character to be converted.
char *s; -- Returned string.
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
Options
NONE
Return Codes
ERR_OK -- No error occurred.
Additional Information Return Codes
ERR_OK -- No error occurred.
Description
This routine converts characters into strings. Each of the non-
printable characters are converted into a coded string. For
example, the character '\0' would return as "[NUL]". This
routine is useful in EveryChar, which was the main reason this
routine was written. The following lists how each of the non-
printable characters are returned.
0 - [NUL]
1 - [SOH]
2 - [STX]
3 - [ETX]
4 - [EOT]
5 - [ENQ]
6 - [ACK]
7 - [BEL]
8 - [BS]
AvidConvert
37
9 - [HT]
10 - [LF]
11 - [VT]
12 - [FF]
13 - [CR]
14 - [SO]
15 - [SI]
16 - [DLE]
17 - [DC1]
18 - [DC2]
19 - [DC3]
20 - [DC4]
21 - [NAK]
22 - [SYN]
23 - [ETB]
24 - [CAN]
25 - [EM]
26 - [SUB]
27 - [ESC]
28 - [FS]
29 - [GS]
30 - [RS]
31 - [US]
127 - [DEL]
Examples
The following code will print all characters received from the
communication port in a tty like mode.
/*****/
void EveryChar(c)
int c;
/*****/
{
char s[20];
int add_info;
AvidConvert(c, s, &add_info, "");
printf("%s", s);
}
See Also
EveryChar
AvidConvert
38
AvidDrainPort - Drain Communication Port
err = AvidDrainPort(AVID, com, (long)r_drain, (long)e_drain,
(int *)&add_info, opts)
Parameter Description
int err; -- Return code.
AVID -- System parameter that must always be specified.
int com; -- The communications port to drain.
long r_drain; -- The number of seconds to drain the
communication port. The drain time will start
over after each character received. (A repeating
drain)
The parameter constant AVID_NO_TIMEOUT will cause
AvidDrainPort to never stop draining due to a
repeating drain value.
NOTE: AvidDrainPort will drain forever if
AVID_NO_TIMEOUT is used for both 'r_drain' and
'e_drain'.
long e_drain; -- The number of seconds to drain the
communication port. The drain time will NOT start
over after each character received. (An ending
drain)
The parameter constant AVID_NO_TIMEOUT will cause
AvidDrainPort to never stop draining due to an
ending drain value.
NOTE: AvidDrainPort will drain forever if
AVID_NO_TIMEOUT is used for both 'r_drain' and
'e_drain'.
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
Options
NONE
AvidDrainPort
39
Return Codes
ERR_OK -- No error occurred.
ERR_NOT_INITIALIZED -- This error is returned when
AvidInitAutoLibrary is not called before this
routine is called.
ERR_COMM_PACKAGE -- This error can occur when AvidDrainPort
reads from the communication port. When this
error occurs, the parameter 'add_info' will
contain the actual error returned by the
communication package.
ERR_INVALID_PORT -- This error can occur when the
communication port specified in the 'com'
parameter was not a valid opened port.
Additional Information Return Codes
ERR_OK -- No error occurred.
<system err> -- When ERR_COMM_PACKAGE is returned,
'add_info' contains the actual error returned
by the communication package.
Description
This routine drains a communication port. The drain time can be
specified as a repeating timeout or as an ending timeout. This
routine can be called out explicitly or it is possible to drain a
communication line directly from AvidSendSearch by using
switches.
Examples
The following example will drain the communication port until
there is 2 seconds of communications silents. If there is not
communications silents for 2 seconds, the drain will stop after
20 seconds.
err = AvidDrainPort(AVID, com, (long)2, (long)20, &add_info, "");
The following example will drain the communication port until
there is 4 seconds of communications silents. If there is never
communications silents this call will never return.
AvidDrainPort
40
err = AvidDrainPort(AVID, com, (long)4, AVID_NO_TIMEOUT,
&add_info, "");
The following example will drain for 5 seconds paying no
attention to the communication activity.
err = AvidDrainPort(AVID, com, AVID_NO_TIMEOUT, (long)5,
&add_info, "");
See Also
AvidSendSearch (Especially .D and .d switches)
AvidDrainPort
41
AvidExitAutoLibrary - Exit AutoLibrary
err = AvidExitAutoLibrary(AVID, (int *)&add_info, opts)
Parameter Description
int err; -- Return code.
AVID -- System parameter that must always be specified.
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
Options
NONE
Return Codes
ERR_OK -- No error occurred.
ERR_NOT_INITIALIZED -- This error is returned when
AvidInitAutoLibrary is not called before this
routine is called.
ERR_CANNOT_EXIT -- All of the AutoLibrary ports need to be
closed first with AvidClosePort.
Additional Information Return Codes
ERR_OK -- No error occurred.
Description
This routine exits from the AutoLibrary(tm) Program-Playback
tool. All memory and resources used by this tool are returned.
Once AvidExitAutoLibrary is called, it is possible to call
AvidInitAutoLibrary to again initialize the AutoLibrary(tm)
Program-Playback tool.
Examples
The following call is made after the last opened port is closed
by AvidClosePort.
AvidExitAutoLibrary
42
err = AvidExitAutoLibrary(AVID, &add_info, "");
See Also
AvidInitAutoLibrary
AvidExitAutoLibrary
43
AvidGetFromHoldArea - Get Characters from Hold Area
actual = AvidGetFromHoldArea(AVID, com, (long)pos, (long)size,
s, (int *)&add_info, opts)
Parameter Description
long actual; -- This is the actual number of characters in s.
This may not match strlen(s) if null characters
were received from the hold area.
AVID -- System parameter that must always be specified.
int com; -- The AutoLibrary communications port.
long pos; -- This is the position in the hold area to start
getting characters that will make up the string
returned.
long size; -- This is the size of the string to get.
char *s; -- This is the string that was built by
AvidGetFromHoldArea.
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
Options
NONE
Return Codes
<actual> -- Returns the number of characters in the string.
Zero is returned when there is no characters in the
hold area or if erroneous values where passed to it.
For example, negative seven for the position or a
position that is specified outside the hold area
boundaries.
Additional Information Return Codes
ERR_OK -- No error occurred.
Description
AvidGetFromHoldArea
44
This routine will get characters from the hold area. It is also
possible to capture characters directly from the AvidSendSearch
routine by specifying switches.
Examples
The following example will get 5 characters from the hold area
starting at position 3. If the hold area had the characters
"0123456789", 'capture' would have the string "34567".
actual = AvidGetFromHoldArea(AVID, com, (long)3, (long)5,
capture, &add_info, "");
After the following example executed 'capture' would have the
string "12" given the same hold area as above.
actual = AvidGetFromHoldArea(AVID, com, (long)8, (long)2,
capture, &add_info, "");
See Also
AvidSendSearch (Especially +c and -c switches)
AvidGetFromHoldArea
45
AvidInitAutoLibrary - Initialize AutoLibrary
err = AvidInitAutoLibrary(AVID, (int *)&add_info, opts)
Parameter Description
int err; -- Return code.
AVID -- System parameter that must always be specified.
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
Options
_b'num' -- This changes the number of milliseconds to delay
before sending the first character of the string. The
specified value will replace the default permanently.
(Default is 0).
_B'num' -- This changes the number of milliseconds to delay
between each character sent. The specified value will
replace the default permanently. (Default is 0).
+h'num' -- This option changes the size of the hold area. This
value will automatically be increased if the chosen
value is less than AvidSendSearch's capture size
(SEND_SEARCH_CAPTURE_MAX). (Default is 512).
+R -- This switch is used after your copy of AutoLibrary
is registered. This will initialize AutoLibrary
without printing "Unregistered Evaluation Copy" to the
screen.
Unregistered users are not allowed to use this switch.
However, if the actual printing of "Unregistered
Evaluation Copy" interferes with your ability to
evaluate AutoLibrary, you may temporarily use this
switch.
Note: The +R switch does not change the functionality
of AutoLibrary. Both the registered and unregistered
initialization methods result in fully functional
software.
AvidInitAutoLibrary
46
Return Codes
ERR_OK -- No error occurred.
ERR_ALREADY_INITIALIZED -- This routine cannot be called more
than once without first call
AvidExitAutoLibrary.
Additional Information Return Codes
ERR_OK -- No error occurred.
Description
This routine is used to initialize the AutoLibrary(tm) Program-
Playback tool. This routine must be the first routine called.
Use AvidExitAutoLibrary to uninitialize.
Examples
The following example initializes AutoLibrary for the
unregistered libraries. (The unregistered libraries will print
the message "Unregistered Evaluation Copy".
err = AvidInitAutoLibrary(AVID, &add_info, "");
The following example initialize AutoLibrary for the registered
libraries. The +R switch causes the printf to not occur.
err = AvidInitAutoLibrary(AVID, &add_info,"+R");
See Also
AvidExitAutoLibrary
AvidInitAutoLibrary
47
AvidLogInfo - Log information to file or screen.
val = AvidLogInfo(AVID, com, title, user_code,
(int *)&add_info, opts)
Parameter Description
int val; -- Return code or if *E switch is specified, the
number of logged errors is returned.
AVID -- System parameter that must always be specified.
int com; -- The AutoLibrary communication port.
char *title; -- A one line string to log.
int user_code; -- An integer value that can be used in any way to
add information to the log entry.
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
Options
+p -- Print the log message to the screen using printf. This
switch guarantees the message will be printed, regardless of
the current default. The default is to print, but this can
be changed by AvidLogOpen.
-p -- Do not print the message to the screen. This switch
guarantees the message will not be printed, regardless of
the current default. The default is to print, but this can
be changed by AvidLogOpen.
+E -- After the error has been logged, 'exit(1)' is called to
abort further processing. This switch guarantees processing
will abort, regardless of the current default. The default
is to continue processing, but this can be changed by
AvidLogOpen. This switch will only have effect on error
messages, i.e., messages that use the *E switch.
-E -- After message has been logged, continue processing. This
switch guarantees processing will continue, regardless of
the current default. The default is to continue processing,
but this can be changed by AvidLogOpen.
AvidLogInfo
48
+L -- Log the message to the log file. This switch guarantees
the message will be logged, regardless of the current
default. The default is to log all messages, but this can
be changed by AvidLogOpen. Also, this switch is only valid
after AvidLogOpen is called to open the log file.
-L -- Do not log message in the log file. This switch
guarantees the message will not be logged, regardless of the
current default. The default is to log all messages, but
this can be changed by AvidLogOpen.
*E -- This option directs AvidLogInfo to print the log entry as
an error. The string "ERROR(int)," is added to the log
message. AvidLogInfo returns the number of errors logged
when this switch is specified. The integer that is printed
as part of ERROR(int) is the 'user_code' parameter.
*T -- This option directs AvidLogInfo to add a date and time
stamp to the log entry.
*L -- This option directs AvidLogInfo to print information that
identifies where AvidLogInfo was called from in your source
code. The line number and source file name will be added to
the log message. With this information, errors can be
traced back to the exact source line they occurred.
Return Codes
<Positive Number> -- The number of logged errors. This is
possible only when the *E switch is used.
ERR_OK -- No error occurred.
ERR_NOT_INITIALIZED -- This error is returned when
AvidInitAutoLibrary is not called before this
routine is called.
ERR_WRITING -- There was a problem writing to the log
file.
ERR_INVALID_PORT -- This error can occur when the
communication port specified in the 'com'
parameter was not a valid opened port.
Additional Information Return Codes
AvidLogInfo
49
ERR_OK -- No error occurred.
<system err> -- When ERR_WRITING is returned, 'add_info'
will contain the system error that was
returned by the clib call to 'fprintf'.
Description
This routine makes it possible to log a message to a file, to the
screen, or to both. Switches are used to customize the format of
a log message. The examples below will show some of the ways
this routine can be used.
Examples
The following example will use this routine to log when a test
has started. The 'user_code' is set to zero and is not used,
since the *E switch was not specified. The *T switch will add a
time stamp to the logged message, which will document when the
test started. The output from this call is also shown.
/* Log the type of test and when it started. */
AvidLogInfo(AVID, com, "Executing screen location test",
0, &add_info, "*T");
OUTPUT:
Mon Jun 24 17:36:12 1991,Executing screen location test
The following example will log an error. Notice the error
returned from AvidSendSearch is specified as the 'user_code'
parameter. This will help determine the cause of the error. The
switches *E, *T, and *L add more information to the error
message. The output from this call is also shown.
AvidLogInfo
50
/* Make sure the cursor is where we placed it with ESC b */
sprintf(temp_buf, ".s'%sb' 1w'C' -c'6'", ESC_CODE);
if ((err = AvidSendSearch(AVID, com,
(long)10, (long)30, &add_info, temp_buf,
(long *)&actual, capture)) <= ERR_SNF) {
num_logged = AvidLogInfo(AVID, com,
"Cursor not placed correctly",
err, &add_info, "*ETL");
}
OUTPUT:
ERROR(-1002),Mon Jun 24 17:36:12 1991,(TST.C,74),Cursor not
placed correctly
The following example does not log the entry to the log file.
Instead, the message is printed to the screen. The output from
this call is also shown.
/* Print Welcome message. */
AvidLogInfo(AVID, com, "Welcome", 0, &add_info, "-L");
OUTPUT:
Welcome
See Also
AvidLogOpen
AvidLogInfo
51
AvidLogOpen - Open a Log File.
err = AvidLogOpen(AVID, com, filename, (int *)&add_info, opts)
Parameter Description
int err; -- Return code.
AVID -- System parameter that must always be
specified.
int com; -- The AutoLibrary communication port.
char *filename; -- The file to open as a log file.
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
Options
-p -- This option changes the default for AvidLogInfo to not
print the log message to the screen. The normal default
prints messages to the screen using 'printf'.
+E -- This option changes the default for AvidLogInfo to abort
processing after the error has been logged. The normal
default continues processing after logging errors. This
switch will only have effect on error messages, i.e., those
messages that use the *E switch.
Return Codes
ERR_OK -- No error occurred.
ERR_NOT_INITIALIZED -- This error is returned when
AvidInitAutoLibrary is not called before this
routine is called.
ERR_OPENING -- There was a problem opening the log file.
ERR_INVALID_PORT -- This error can occur when the
communication port specified in the 'com'
parameter was not a valid opened port.
Additional Information Return Codes
AvidLogOpen
52
ERR_OK -- No error occurred.
Description
This routine is used to open a log file that AvidLogInfo will
use. The switches that this routine supports allows AvidLogInfo
to have different defaults. AvidLogOpen is needed only to open a
log file and is not required before AvidLogInfo is called.
However, if AvidLogOpen is not called, AvidLogInfo is restricted
to logging messages to the screen.
Examples
The following example will open a log file called "logfile".
err = AvidLogOpen(AVID, com, "logfile", &add_info, "");
The following example will again open a log file called
"logfile". However, it will also change the defaults for
AvidLogInfo to not print log entries to the screen and to abort
processing after logging error messages.
err = AvidLogOpen(AVID, com, "logfile", &add_info, "-p +E");
See Also
AvidLogInfo
AvidLogOpen
53
AvidOpenPort - Open Communication Port
com = AvidOpenPort(AVID, device, (int *)&add_info, opts)
Parameter Description
int com; -- This is the AutoLibrary port identification
number that is used by all of the AutoLibrary
routines.
AVID -- System parameter that must always be specified.
char *device; -- This is the device name of the communication
port to open.
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
Options
_b'num' -- This changes the number of milliseconds to delay
before sending the first character of the string. The
specified value will replace the default permanently
for this port. (Default is 0).
_B'num' -- This changes the number of milliseconds to delay
between each character sent. The specified value will
replace the default permanently for this port. (Default
is 0).
+h'num' -- This option changes the size of the hold area for
this port. This value will automatically be increased
if the chosen value is less than AvidSendSearch's
capture size (SEND_SEARCH_CAPTURE_MAX). (Default is
512).
Options (Depends on implementation of CommInterfaceOpen)
.b'baud' -- This will change the baud rate from the default of
9600 to the specified value. Choose from: 50, 75,
110, 134.5, 150, 300, 600, 1200, 1800, 2000, 2400,
3600, 4800, 7200, 9600, 19200. (Default is 9600).
.1 -- One stop bit will be used. (Default).
AvidOpenPort
54
.2 -- Two stop bits will be used. (Default is 1).
.7 -- Seven bits per word. (Default is 8).
.8 -- Eight bits per word. (Default).
.e -- Even parity will be used. (Default is odd).
.o -- Odd parity will be used. (Default).
.n -- No parity will be used. (Default is odd).
-S -- This will cause the 7th bit to NOT be stripped.
(Default is to strip).
+S -- This will cause the 7th bit to be stripped.
(Default).
+X -- This will cause software (xon-xoff) flow control to
be used. (Default).
-X -- This will cause software (xon-xoff) flow control to
not be used. (Default is on).
.T -- This will cause dtr to be asserted. (Default is not
to).
rx'num' -- Changes the default receive buffer size. (Default is
8192).
tx'num' -- Changes the default transmit buffer size. (Default
is 512).
The Greenleaf Comm Library
This is a commerical communication package provided by Greenleaf
Software, Inc. 16479 Dallas Parkway, Bent Tree Tower Two, Suite
570, Dallas, TX 75248, (214)248-2561.
(Note: This is just one of many good communication packages. It
is easy to write interface routines for the AutoLibrary Program-
Playback Tool, so don't feel you are tied to any one
communication package.)
Options Supported
AvidOpenPort
55
.b'num' .1 .2 .7 .8 .e .o .n -S +S +X -X .T rx'num'
tx'num'
Baud rates supported are: 50, 75, 110, 134.5, 150, 300, 600,
1200, 1800, 2000, 2400, 3600, 4800, 7200, 9600, 19200. (Default
is 9600).
The ifsrtcl.lib Comm Library
This is a basic communication package supplied with this product
that combines the interface routines with asynchronous
communication software. It is intended to allow you to evaluate
AutoLibrary and make it easy to get started.
ERR_QUEUE_FULL is returned if the send queue is full.
ERR_INVALID_PORT is returned if something other than com1 or com2
is specified.
Options Supported
.b'num' .1 .2 .7 .8 .e .o .n
Baud rates supported are: 110, 150, 300, 600, 1200, 2400, 4800,
9600. (Default is 9600).
Also, the default is to use receive Xon/Xoff, and cannot be
changed. Transmit Xon/Xoff is not supported, i.e., this package
will ignore Xoff characters. However, the Xon/Xoff the protocol
will be used if characters are received faster than they are
processed. The restriction works out ok because you can control
how many characters you send but cannot control how many and how
fast characters are received.
Return Codes
<Positive number> -- No error occurred. The positive number is
the AutoLibrary port number.
ERR_NOT_INITIALIZED -- This error is returned when
AvidInitAutoLibrary is not called before this
routine is called.
ERR_COMM_PACKAGE -- This error can occur when the
communication package cannot open the
communication port correctly. When this
error occurs, the parameter 'add_info' will
AvidOpenPort
56
contain the actual error returned by the
communication package.
ERR_EXCEEDED_COMLIST_SIZE -- This will occur when an attempt
is made to open more than
COMLIST_SIZE. The default for this
value is 30, which can be changed
by re-compiling AutoLibrary.
ERR_NO_MEMORY -- This will occur when there is no more
memory to allocate required data structures.
Additional Information Return Codes
ERR_OK -- No error occurred.
<system err> -- When ERR_COMM_PACKAGE is returned,
'add_info' contains the actual error returned
by the communication package.
Description
This routine opens an AutoLibrary communication port. This
routine creates the required data structures to support
automation and calls CommInterfaceOpen to open the hardware port
of the communication package supplied.
IMPORTANT: Note: the list of options for this routine are
dependent on how the interface library routine CommInterfaceOpen
was implemented.
Examples
The following example opens the communication port at 9600 baud,
one stop bit, eight bits per word, no parity, strip 7th bit, and
do not use hardware flow control.
com = AvidOpenPort(AVID, "com1", &add_info,
".b'9600' .1 .8 .n +S -H");
See Also
AvidClosePort, CommInterfaceOpen
AvidOpenPort
57
AvidProcessOptions - Parse an Option Parameter List
o_char = AvidProcessOptions(AVID, o_list, target,
(char *)&control, arg_s, (int *)&start)
Parameter Description
char o_char; -- This is the character part of the option. This
will have a '\0' (null) value when there are no
more options to process. If the switch was -
X'good', for example, 'o_char' would return 'X'.
AVID -- System parameter that must always be specified.
char *o_list; -- This is the list of options.
char *target; -- Look only for the option specified as the
target. This makes it possible to scan for the
target option without using a while loop.
char *control; -- This is the option control character of the
parsed option. If the switch was -X'good', for
example, 'control' would return '-'.
char *arg_s; -- This is where the options argument is written.
If the switch does not have an argument, a null
string is returned. If the switch was -X'good',
for example, 'arg_s' would return "good".
int *start; -- The location to start parsing in the option
list. This parameter must be initialized to zero,
then left alone. It is used internally by
AvidProcessOptions to track which switch to return
next.
Options
NONE
Return Codes
Not applicable.
Description
AvidProcessOptions
58
This is the routine that parses the option parameters that every
AutoLibrary routine has. AvidProcessOptions is not needed to
support automation, however, it has been documented and made
public because it is a nice routine of general utility.
AvidProcessOptions
59
Examples
AvidProcessOptions can be used two ways. This example shows the
first way, where the 'target' parameter is given a specific
switch to look for, namely, "-L". AvidProcessOptions won't
return until it finds this specific switch or it returns NULL.
This method eliminates the need to call AvidProcessOptions in a
loop.
/* Find out if over night tests should be done. */
if (AvidProcessOptions(AVID, arg_str, "-L",
&control, arg, &start) != '\0')
long_version = TRUE;
else
long_version = FALSE;
The second way to use AvidProcessOptions is to call it in a while
loop. The 'target' parameter is left empty, which tells
AvidProcessOptions to return the next switch. The 'sc' variable
returns with the switch character and the 'control' variable
returns with the control character. It is important to
initialize the 'start' parameter to zero, because this variable
is used to determine which switch to return. If, for example,
the 'start' parameter was set to zero inside the while loop,
AvidProcessOptions would always return the first switch.
/* Find out what kind of batch mode testing to do. */
start=0; /* Required by AvidProcessOptions. */
while ((sc=AvidProcessOptions(AVID, arg_str, "",
&control, arg, &start)) != '\0') {
/* Execute print test if "+P" switch was specified. */
if ((control == '+') && (sc == 'P')) {
initialize_testing(com);
test_scr_print(com, 20, 80);
}
/* Execute screen attributes test if "-a" switch was
specified. */
if ((control == '-') && (sc == 'a')) {
initialize_testing(com);
test_scr_attribs(com);
}
}
AvidProcessOptions
60
AvidRead - Read a Character
c = AvidRead(AVID, com, (long)r_timeout, (long)e_timeout,
(int *)&add_info, opts)
Parameter Description
int c; -- The character received is returned.
AVID -- System parameter that must always be
specified.
int com; -- The AutoLibrary port number.
long r_timeout; -- The number of seconds to wait for a
character. The timeout value starts over
after each character received.
long e_timeout; -- The total number of seconds wait for a
character plus the current number of seconds.
The timeout value does NOT start over after
each character received.
AvidRead is different from the other
AutoLibrary routines that use an ending
timeout. For AvidRead the current number of
seconds since Jan 1, 1970 must be added to
the delay before making the call. Use the
following code segment.
time(seconds);
if (e_timeout != AVID_NO_TIMEOUT)
e_timeout = e_timeout + seconds;
( make call to AvidRead here )
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
Options
NONE
Return Codes
AvidRead
61
<character> -- No error occurred.
ERR_NOT_INITIALIZED -- This error is returned when
AvidInitAutoLibrary is not called before this
routine is called.
ERR_COMM_PACKAGE -- This error can occur when the
communication package cannot read the
communication port correctly. When this
error occurs, the parameter 'add_info' will
contain the actual error returned by the
communication package.
ERR_EOF -- There were no more characters to read or a
timeout occurred. If a timeout occurred,
'add_info' will have the values
ERR_REPEAT_TIMEOUT or ERR_ENDING_TIMEOUT.
ERR_INVALID_PORT -- This error can occur when the
communication port specified in the 'com'
parameter was not a valid opened port.
Additional Information Return Codes
ERR_OK -- No error occurred.
<system err> -- When ERR_COMM_PACKAGE is returned,
'add_info' will contain the actual error
returned by the communication package.
ERR_REPEAT_TIMEOUT -- When ERR_EOF is returned and the cause for
the timeout is a Repeating Timeout, this is
the value returned.
ERR_ENDING_TIMEOUT -- When ERR_EOF is returned and the cause is
an Ending Timeout, this is the value
returned.
Description
This routine will read one character at a time from the
communication port. This routine is supplied only for
completeness and is not required for automation. Internally
AvidSendSearch and AvidDrainPort call this routine to read
characters. The ending timeout must be fixed up as described
above in the parameter definition of 'e_timeout'.
AvidRead
62
AvidSendSearch should be used to read characters into a buffer,
instead of AvidRead.
Examples
See the source code for AvidSendSearch or AvidDrainPort.
See Also
CommInterfaceRead
AvidRead
63
AvidRegisterSend - Register a String to Send
err = AvidRegisterSend(AVID, com, s_string,
(int *)&add_info, opts)
Parameter Description
int err; -- Return code.
AVID -- System parameter that must always be
specified.
int com; -- The AutoLibrary port number.
char *s_string; -- This is the string to be sent by
AvidSendSearch.
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
Options
_b'num' -- This changes the number of milliseconds to delay
before sending the first character of the string. The
specified value will replace the default only for this
invocation. Use AvidInitAutoLibrary or AvidOpenPort to
change the defaults permanently. (Default is 0).
_B'num' -- This changes the number of milliseconds to delay
between each character sent. The specified value will
replace the default only for this invocation. Use
AvidInitAutoLibrary or AvidOpenPort to change the
defaults permanently. (Default is 0).
.N'num' -- This is the number of null characters in the string.
For example, .N'3' would be specified for the string
"\n\r\0\0abc\0".
Return Codes
ERR_OK -- No error occurred.
ERR_NOT_INITIALIZED -- This error is returned when
AvidInitAutoLibrary is not called before this
routine is called.
AvidRegisterSend
64
ERR_NO_MEMORY -- This error will occur when there is not
enough memory to allocate the required data
structures.
ERR_INVALID_PORT -- This error can occur when the
communication port specified in the 'com'
parameter was not a valid opened port.
Additional Information Return Codes
ERR_OK -- No error occurred.
Description
This routine will register a string to be sent when
AvidSendSearch is called. AvidRegisterSend does not send the
string, it puts it into a linked list.
Note that calling AvidRegisterSend is optional since send strings
can be registered directly from AvidSendSearch by using switches.
Examples
The following example registers the specified string for
AvidSendSearch to send.
err = AvidRegisterSend(AVID, com, "hi there\r", &add_info, "");
See Also
AvidRegisterWait, AvidSendSearch (Especially the .s switch)
AvidRegisterSend
65
AvidRegisterWait - Register a Wait String
err = AvidRegisterWait(AVID, com, r_num, w_string,
(int *)&add_info, opts)
Parameter Description
int err; -- Return code.
AVID -- System parameter that must always be
specified.
int com; -- The AutoLibrary port number.
int r_num; -- This is the registered number to be
returned by AvidSendSearch if the string is
found.
Numbers from 20,000 to max integer are
reserved by Avid Software for future use and
internal implementations.
char *w_string; -- This is the string to add to the wait-
list. If this string is found by
AvidSendSearch, the registered value will be
returned.
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
Options
.N'num' -- This is the number of null characters in the string.
For example, .N'3' would be specified for the string
"\n\r\0\0abc\0".
Return Codes
ERR_OK -- No error occurred.
ERR_NOT_INITIALIZED -- This error is returned when
AvidInitAutoLibrary is not called before this
routine is called.
AvidRegisterWait
66
ERR_NO_MEMORY -- This error will occur when there is not
enough memory to allocate the required data
structures.
ERR_INVALID_PORT -- This error can occur when the
communication port specified in the 'com'
parameter was not a valid opened port.
Additional Information Return Codes
ERR_OK -- No error occurred.
Description
This routine is used to register a string for AvidSendSearch to
scan for. This routine puts the wait string in a linked list.
This routine can be called as many times as required. Each time
it is called another wait string gets added to the linked list.
The value that is registered with AvidRegisterWait is the same
value that AvidSendSearch will return if the wait string is
found. Wait strings can also be specified as a switch to
AvidSendSearch. This way calling AvidRegisterWait directly is
not required.
Examples
The following example registers the specified string for
AvidSendSearch to wait for. If the string is found,
AvidSendSearch will return 100.
err = AvidRegisterWait(AVID, com, 100,
"This is a string", &add_info, "");
See Also
AvidRegisterSend, AvidSendSearch (Especially the 1w switch)
AvidRegisterWait
67
AvidSend - Send a String
err = AvidSend(AVID, com, s, (int *)&add_info, opts)
Parameter Description
int err; -- Return code.
AVID -- System parameter that must always be specified.
int com; -- The AutoLibrary port number.
char *s; -- This is the string to send.
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
Options
_b'num' -- This changes the number of milliseconds to delay
before sending the first character of the string. The
specified value will replace the default only for this
invocation. Use AvidInitAutoLibrary or AvidOpenPort to
change the defaults permanently. (Default is 0).
_B'num' -- This changes the number of milliseconds to delay
between each character sent. The specified value will
replace the default only for this invocation. Use
AvidInitAutoLibrary or AvidOpenPort to change the
defaults permanently. (Default is 0).
.N'num' -- This is the number of null characters in the string.
For example, .N'3' would be specified for the string
"\n\r\0\0abc\0".
Return Codes
ERR_OK -- No error occurred.
ERR_NOT_INITIALIZED -- This error is returned when
AvidInitAutoLibrary is not called before this
routine is called.
ERR_COMM_PACKAGE -- This error can occur when the
communication package cannot send through the
AvidSend
68
communication port correctly. When this
error occurs, the parameter 'add_info' will
contain the actual error returned by the
communication package.
ERR_NO_STRING_SPECIFIED -- This error occurs when there was no
string specified.
ERR_INVALID_PORT -- This error can occur when the
communication port specified in the 'com'
parameter was not a valid opened port.
Additional Information Return Codes
ERR_OK -- No error occurred.
<system err> -- When ERR_COMM_PACKAGE is returned, 'add_info'
contains the actual error returned by the
communication package.
Description
This routine sends the specified string.
Examples
The following example sends the specified string.
err = AvidSend(AVID, com, "Hello\r", &add_info, "");
See Also
AvidRegisterSend, CommInterfaceSend, AvidSendSearch
AvidSend
69
AvidSendSearch - Send Strings then Search
s_found = AvidSendSearch(AVID, com,
(long)r_timeout, (long)e_timeout, (int *)&add_info,
opts, (long *)&actual, cap)
Parameter Description
int s_found; -- The registered value of the string that
was found. ERR_SNF, which is equal to zero,
is returned if none of the registered strings
were found.
AVID -- System parameter that must always be
specified.
int com; -- The opened communication port.
long r_timeout; -- The number of seconds to scan for the
strings in the wait-list. The timeout value
starts over after each character received.
(A repeating timeout)
The parameter constant AVID_NO_TIMEOUT will
cause AvidSendSearch to never timeout due to
a repeating timeout.
long e_timeout; -- The number of seconds to scan for the
strings in the wait-list. The timeout value
does NOT start over after each character
received. (An ending timeout)
The parameter constant AVID_NO_TIMEOUT will
cause AvidSendSearch to never timeout due to
an ending timeout.
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
<long *actual;> -- This is the actual number of characters
captured. May not equal strlen(cap) if cap
received null characters as part of the data.
(This parameter is optional see the +c and
-c options below.)
AvidSendSearch
70
<char *cap;> -- This is the capture string. (This
parameter is optional, see the +c and -c
options below.)
Options
+c'size' -- This will cause AvidSendSearch to capture each
received character until 'size' number of
characters have been received. The captured
string will be smaller that 'size' if a timeout
occurs or one of the strings in the wait-list was
found.
-c'size' -- This will cause AvidSendSearch to capture
received characters until one of the strings in
the wait-list was found or a timeout occurred.
Truncation will occur if more than 'size' number
of characters are received before AvidSendSearch
is finished.
.d'drain_time' -- This is the drain time in seconds. The drain
time will start over with each new received
character. (Repeating drain)
.D'drain_time' -- This is the drain time in seconds. The drain
time will NOT start over with each new received
character. (Ending drain)
1w'string' -- This is a wait string. AvidSendSearch will
return 1 if the string is found. Numbers 1
through 9 are valid for this option. For example,
2w'string' will register 'string' with 2 and
9w'string' will register it with 9.
.s'string' -- This is a send string.
Return Codes
<registered value> -- When one of the wait strings is found, the
registered value is returned.
ERR_SNF -- SNF (String Not Found). This is returned
when none of the wait strings were found.
The variable 'add_info' can be tested to find
out additional information about why ERR_SNF
was returned. The possible values for
AvidSendSearch
71
'add_info' are ERR_ENDING_TIMEOUT,
ERR_REPEAT_TIMEOUT, and ERR_CAPTURE_FULL.
ERR_NOT_INITIALIZED -- This error is returned when
AvidInitAutoLibrary is not called before this
routine is called.
ERR_NO_MEMORY -- This error can be returned if the .s or 1w
switch is used. It is possible for
AvidRegisterSend and AvidRegisterWait to not
have the required memory to allocate data
structures.
ERR_COMM_PACKAGE -- This error can occur when the strings in
the send-list are being sent or when
characters are being read looking for the
strings in the wait-list. When this error
occurs, the parameter 'add_info' will contain
the actual error returned by the
communication package.
ERR_INVALID_PORT -- This error can occur when the
communication port specified in the 'com'
parameter was not a valid opened port.
Additional Information Return Codes
ERR_OK -- No error occurred.
<system err> -- When ERR_COMM_PACKAGE is returned,
'add_info' contains the actual error returned
by the communication package.
ERR_REPEAT_TIMEOUT -- When ERR_SNF is returned and the cause for
the timeout is a Repeating Timeout, this is
the value returned.
ERR_ENDING_TIMEOUT -- When ERR_SNF is returned and the cause is
an Ending Timeout, this is the value
returned.
ERR_CAPTURE_FULL -- When ERR_SNF is returned and the cause is
due to a full capture string, this is the
value returned.
Description
AvidSendSearch
72
This routine is the main routine used for automation.
AvidSendSearch sends all of the strings in the send-list, then
scans for the strings in the wait-list. If one of the strings in
the wait-list is found, AvidSendSearch returns with that wait
string's registered value. If none of the wait strings are found
within the specified timeout period, AvidSendSearch returns with
ERR_SNF. (SNF is String Not Found).
It is possible to capture characters while AvidSendSearch is
scanning for the strings in the wait-list using the switches +c
or -c. It is also possible to specify drain times with switches.
If specified, draining will occur after one of the strings in the
wait-list is found.
The send-list and wait-list can be built by calling
AvidRegisterSend and AvidRegisterWait, respectively. The send-
list and wait-list can also be built in AvidSendSearch by using
switches. Using switches eliminates the need to call
AvidRegisterSend and AvidRegisterWait.
Examples
The following example sends the string "exit\r" then waits for
the string "login:". Calls to AvidRegisterSend and
AvidRegisterWait are used to add the strings to the linked list
for AvidSendSearch.
/* Register the send string. */
AvidRegisterSend(AVID, com, "exit\r", &add_info, "");
/* Register the wait string. */
AvidRegisterWait(AVID, com, 1, "login:", &add_info, "");
/* Send the exit command, then wait for the login: prompt. */
if (AvidSendSearch(AVID, com, (long)5, (long)45,
&add_info, "") <= ERR_SNF)
printf("Exit failed\n");
The following example is the same as the one above, except the
send string and wait string are registered by using
AvidSendSearch switches.
/* Send the exit command, then wait for the login: prompt. */
if (AvidSendSearch(AVID, com, (long)5, (long)45,
&add_info, ".s'exit\r' 1w'login:'") <= ERR_SNF)
printf("Exit failed\n");
AvidSendSearch
73
Notice in the following example that it is possible to add more
than one wait string using AvidRegisterWait. AvidSendSearch will
return the registered string value of the string it finds. In
this example, either 1 or 2.
/* Register the send string. */
AvidRegisterSend(AVID, com, "exit\r", &add_info, "");
/* Register the wait string. */
AvidRegisterWait(AVID, com, 1, "login:", &add_info, "");
/* Register the wait string. */
AvidRegisterWait(AVID, com, 2, "Enter Data Switch Number:",
&add_info, "");
/* Send the exit command, then wait for the login: prompt. */
if (AvidSendSearch(AVID, com, (long)5, (long)45,
&add_info, "") <= ERR_SNF)
printf("Exit failed\n");
The following is the same as the example above except
AvidSendSearch is used to register the wait strings.
/* Register the send string. */
AvidRegisterSend(AVID, com, "exit\r", &add_info, "");
/* Send the exit command, then wait for the login: prompt. */
if (AvidSendSearch(AVID, com, (long)5, (long)45, &add_info,
"1w'login:' 2w'Enter Data Switch Number:'") <= ERR_SNF)
printf("Exit failed\n");
The following example shows how to capture information using the
negative capture switch. The negative capture is used when the
wait string follows the information that needs to be captured.
Suppose, for example, sending the command 'weather\r' is a host
command that displays todays weather forecast. A segment of what
this command returns might be...
November 17, 1990
Sunny
Wind gusts to 30 mph
Temperature 43 F
No Rain
or the following segment is also possible...
November 18, 1990
AvidSendSearch
74
Partly cloudy
Mild wind of 2 mph
Temperature 35 F
No Rain
The wind speed needs to be captured. However, the text before
the wind speed is never consistent. Therefore, it is impossible
to key off of a string before the value to be captured. The
string "mph", however, is always displayed after the wind speed.
With this consistency, it is possible to capture the wind speed
with a negative capture string. The following example will do
it.
if (AvidSendSearch(AVID, com, (long)5, (long)45, &add_info,
".s'weather\r' 1w'mph' -c'3'",
(long *)&actual, captured) <= ERR_SNF)
printf("Failed\n");
The capture string for the first sample segment would have the
string "30 " and for the second sample segment would have the
string " 2 ". In each case, the capture string is the last 3
characters before the string 'mph'.
A positive capture is used when the string to key off of is
before the information to be captured. Using the sample segments
from the weather example, notice that the string "Temperature" is
always displayed before the temperature. Therefore, a positive
capture can be done. The following code segment will do it.
if (AvidSendSearch(AVID, com, (long)5, (long)45, &add_info,
"1w'Temperature'") <= ERR_SNF)
printf("Failed\n");
if (AvidSendSearch(AVID, com, (long)5, (long)45, &add_info,
"+c'4' 1w'F' .d'1' .D'10'",
(long *)&actual, captured) < ERR_SNF)
printf("Failed\n");
The first call to AvidSendSearch continues from where the wind
speed was captured to the string "Temperature". The second call
to AvidSendSearch captures the next 4 characters. In case the
temperature is in the 100's, 4 characters are captured. The C
function sscanf can be used to filter out the trailing character
if it is not valid.
Notice that the wait switch 1w'F' was also specified. This will
cause AvidSendSearch to return if the string "F" is found. Also,
AvidSendSearch
75
notice that the drain switches .d'1' and .D'10' were specified.
These switches will cause the rest of the 'weather' command to be
read in and ignored. In this example, the drain switches would
cause 'No Rain' to be ignored.
See Also
AvidRegisterSend, AvidRegisterWait, AvidDrainPort
AvidSendSearch
76
AvidVersion - Print Version and Copyright Information
err = AvidVersion(AVID, (int *)&add_info, opts)
Parameter Description
int err; -- Return code.
AVID -- System parameter that must always be specified.
int *add_info; -- Additional return information.
char *opts; -- This is the input parameter for options.
Options
NONE
Return Codes
ERR_OK -- No error occurred.
Additional Information Return Codes
ERR_OK -- No error occurred.
Description
This routine prints the version and copyright information.
Examples
The following example will display the version and copyright
information.
err = AvidVersion(AVID, &add_info, "");
AvidVersion
77
EveryChar - Called with Every Character Received
(void) EveryChar(c)
Parameter Description
int c; -- The character that was received.
Options
Not Applicable
Return Codes
Not Applicable
Description
This routine is different from the other routines: the
AutoLibrary(tm) Program-Playback tool calls this routine with
each received character. You must supply this routine in your
code. This will give your applications the opportunity to print
each received character. If your application does not need this
feature and you do not want the overhead of this routine, simply
remove the call from CommInterfaceRead.
Examples
This example prints each received character to the screen. By
putting this implementation of EveryChar in your application,
each received character will be printed to the screen. EveryChar
could also be used to log every character to a file. Also, see
the example in AvidConvert.
/*****/
void EveryChar(c)
int c;
/*****/
{
printf("%c", c);
}
This example does nothing with each received character, which is
completely valid. Also, it is possible to remove the call to
EveryChar in CommInterfaceRead, which is only important if you do
not want to overhead of calling EveryChar.
EveryChar
78
/*****/
void EveryChar(c)
int c;
/*****/
{
c = c; /* for compiler. */
}
See Also
AvidConvert, CommInterfaceRead
EveryChar
79
Reference Guide for Interface Routines
This section describes the routines that interface to your
communication package and describes how to create interface
routines for other communication packages.
Note: The source code discussed in this section can be found in
intface.c.
80
CommInterfaceClose - Close port
err = CommInterfaceClose(com, (int *)&add_info, opts)
Parameter Description
int err; -- The returned status.
int com; -- The AutoLibrary communication port.
int *add_info; -- Additional return information.
char *opts; -- Options.
Options
See AvidClose
Return Codes
ERR_OK -- No error occurred.
ERR_COMM_PACKAGE -- This error can occur when the
communication package cannot correctly close
the communication port. The parameter
'add_info' will contain the actual
communication packages error code.
Additional Information Return Codes
ERR_OK -- No error occurred.
<system err> -- When ERR_COMM_PACKAGE is returned, this
variable contains the actual error returned by the
communication package.
Description
This routine is used to close the communication port. Your code
must not call this routine directly. This routine will need to
be modified to support your communication package. See the
System Requirements section for a list of supported communication
packages.
Porting to other communication packages
CommInterfaceClose
81
The following sample source code is written to interface with the
Greenleaf CommLib. To support a different communication package,
use this code as a template, then code according to the
specifications of the communication package.
The call to 'asiquit' and the literal ASSUCCESS are unique to the
Greenleaf CommLib and would need to change to support a different
communication package.
When this routine works correctly, ERR_OK must be returned in
'add_info' and as the return status. When this routine fails for
any reason, the return status must be ERR_COMM_PACKAGE. When
ERR_COMM_PACKAGE is returned, 'add_info' should be set to the
actual error from the communication package.
/********************************************************/
int /* The return status. */
CommInterfaceClose (com, info, opts)
int com; /* The AutoLibrary communication port. */
int *info;
char *opts; /* Options. */
/********************************************************/
{
int err;
opts = opts; /* for compiler */
/* Start out with no errors. */
*info = ERR_OK;
err = asiquit (comlist[com]->hw_port);
if (err != ASSUCCESS) {
*info = err;
return(ERR_COMM_PACKAGE);
}
return(ERR_OK);
}
See Also
AvidClosePort, Actual source code.
CommInterfaceClose
82
CommInterfaceOpen - Open Port
err = CommInterfaceOpen(com, device, (int *)&add_info, opts)
Parameter Description
int err; -- The return status.
int com; -- The AutoLibrary port number.
char *device; -- The device name. (For example, "com1" or
"com2".)
int *add_info; -- Additional return information.
char *opts; -- Options.
Options
See AvidOpenPort
Return Codes
ERR_OK -- No error occurred.
ERR_COMM_PACKAGE -- This error occurs when the communication
package cannot open the communication port
correctly. When this error occurs, the
parameter 'add_info' will contain the actual
error returned by the communication package.
Additional Information Return Codes
ERR_OK -- No error occurred.
<system err> -- When ERR_COMM_PACKAGE is returned, 'add_info'
contains the actual error returned by the
communication package.
Description
This routine is used to open the communication port. Your code
must not call this routine directly. This routine will need to
be modified to support your communication package. See the
System Requirements section for a list of supported communication
packages.
CommInterfaceOpen
83
Porting to other communication packages
The best way to describe how to port CommInterfaceOpen is a piece
at a time. You will want to refer to the final version of
CommInterfaceOpen at the end of this section as you read about
this routine. By referring to the final version you will be able
to see where the many code fragments fit in. The following line
of code saves the information required to interface with the
Greenleaf CommLib.
/* Save the Greenleaf port number. */
comlist[com]->hw_port = port_num;
The Greenleaf port number 'port_num' must be saved for later use
in the routines CommInterfaceClose, CommInterfaceRead, and
CommInterfaceSend, since each of these routines make calls to
Greenleaf routines. Note that the Greenleaf port number
'port_num' will not always be equal to the AutoLibrary port
number 'com', i.e., com != comlist[com]->hw_port. The
AutoLibrary port number is used by AutoLibrary routines to get
information from the 'comlist' data structure. Where as, the
Greenleaf port number is used to identify a port number to
communicate with.
The following code segment shows a call that opens a Greenleaf
communication port.
err=asiopen(comlist[com]->hw_port, mode, 8192,
512, 9600, P_ODD, 1, 8, 0, 0);
if (err != ASSUCCESS) {
*info = err;
return(ERR_COMM_PACKAGE);
}
This call opens a communication port with a receive buffer of
8192 bytes, transmit buffer of 512 bytes, baud rate of 9600, odd
parity, one stop bit, and 8 bits per word. This hard coded call
to 'asiopen' is valid, since the AutoLibrary(tm) Program-Playback
tool will work as long as a port gets opened. However, since
hard coded opens are restrictive, switches have been defined to
support opening a communication port in different ways. For
example, the switch -b'4800' requests that the port be opened at
4800 baud. The switch .2 specifies 2 stop bits and rx'1024'
requests a receive buffer of 1K.
CommInterfaceOpen
84
It is the responsibility of CommInterfaceOpen to support these
switches. (It is ok to add switches that are unique to your
communication package.)
Before describing switches, I would like to show the following
implementation of CommInterfaceOpen, which is instructive because
it only shows the required code. Additional code is recommended,
which will be shown later.
CommInterfaceOpen
85
/********************************************************/
int
CommInterfaceOpen (com, device, info, opts)
int com; /* The AutoLibrary communication port. */
char *device; /* The device name. */
int *info;
char *opts; /* Options. */
/********************************************************/
{
int mode, err;
/* Start out with no errors. */
*info = ERR_OK;
/* For Greenleaf COM1 is defined as 0. */
port_num--;
/* Save the port number for closing. */
comlist[com]->hw_port = port_num;
/* No ASCII device names in this comm package. */
comlist[com]->hw_port_name = (char *)NULL;
mode = ASCII | ASINOUT | NORMALRX;
err = asiopen (comlist[com]->hw_port, mode, 8192,
512, 9600, P_ODD, 1, 8, 0, 0);
if (err != ASSUCCESS) {
*info = err;
return(ERR_COMM_PACKAGE);
}
err = asixon(comlist[com]->hw_port, 30, 70, XON, XOFF);
if (err != ASSUCCESS) {
*info = err;
return(ERR_COMM_PACKAGE);
}
return(ERR_OK);
}
The second line of code decrements 'port_num'. This is required
because the Greenleaf CommLib defines 0 for com1, 1 for com2, and
so on. Your communication package may or may not have to
decrement 'port_num'.
CommInterfaceOpen
86
We have already looked at the third line of code. The Greenleaf
port number ('port_num') is saved in the 'comlist' data structure
for later use by the other interface routines.
The forth line of code saves a pointer to the device name in the
'comlist' data structure for later use for the same reasons the
port number is saved. This example sets this value to NULL
because the Greenleaf CommLib does not use device names. If your
communication package uses device names, this field would be used
to save a pointer to the name for the interface routines
CommInterfaceClose, CommInterfaceRead, and CommInterfaceSend.
The device name field 'hw_port_name' is important only if your
communication package refers to ports with text strings instead
of numbers. Just remember that 'comlist[com]->hw_port_name' is a
pointer. Use 'malloc' to dynamically allocate the memory needed
to store the device name, then in CommInterfaceClose free the
memory.
The remaining code in the above example opens a Greenleaf
communication port with hard coded parameters. This
implementation of CommInterfaceOpen contains the bare minimum for
the AutoLibrary(tm) Program-Playback tool to work correctly. If
your application is always to be opened with the same parameters,
an implementation like this may be enough. However, more code is
required if CommInterfaceOpen is to be flexible. When opening a
communication port there are many options to choose from, like
baud rate, number of stop bits, parity, and so on. To support
these different options, we need to add switch processing to
CommInterfaceOpen. For example, the following call to
AvidOpenPort opens communication port one (com1) at 4800 baud and
even parity. The defaults are used for the other parameters.
AvidOpenPort(AVID, "1", &info, ".b'4800' .e");
AvidOpenPort does not process open switches, instead, the
switches are passed directly to CommInterfaceOpen. If we stayed
with the previous implementation of CommInterfaceOpen, the open
switches ".b'4800' .e" would be ignored. To support open
switches, the option parameter needs to be parsed using
AvidProcessOptions. Here is an example of how CommInterfaceOpen
would process the baud rate switch.
CommInterfaceOpen
87
baud = 9600; /* default */
s_num = 0; /* Required for AvidProcessOptions. */
while ((sc = AvidProcessOptions(AVID, opts, "", &control,
temp_buf, &s_num)) != '\0') {
if ((control == '.') && (sc == 'b'))
baud = atoi(temp_buf);
}
First, the variable 'baud' is set to the default of 9600, which
is used if the baud rate switch ( .b'baud' ) is not specified.
The while loop will return each of the switches specified in the
'opts' parameter. The 'if' statement inside the while loop tests
for the baud rate switch. When specified, the new baud rate is
set. The following if statements, when placed inside the while
loop, will set the parity to the desired value.
if ((o_odd[0] == control) && (o_odd[1] == sc))
parity = P_ODD;
if ((o_even[0] == control) && (o_even[1] == sc))
parity = P_EVEN;
The string 'o_odd' is initialized to ".o" and the string 'o_even'
is initialized to ".e". This way the actual switch definition is
done in one spot. The previous example hard coded the baud rate
switch, which has the option string 'o_baud'. The string
'o_baud' will be used in the final version of CommInterfaceOpen.
The constants P_ODD and P_EVEN are defined in the Greenleaf
CommLib. Since your communication package will be different,
these constants will be different.
The following while loop shows how the other open options are
parsed by AvidProcessOptions.
mode = 0;
baud = 9600;
parity = P_ODD;
stop_bits = 1;
word_len = 8;
dtr = 0;
rts = 0;
rx_length = 8192;
tx_length = 512;
strip = ASCII;
xon = TRUE;
CommInterfaceOpen
88
s_num = 0; /* Required for AvidProcessOptions. */
while ((sc = AvidProcessOptions (AVID, opts, "", &control,
temp_buf, &s_num)) != '\0') {
if ((o_strip_yes[0] == control) && (o_strip_yes[1] == sc))
strip = ASCII;
if ((o_strip_no[0] == control) && (o_strip_no[1] == sc))
strip = BINARY;
if ((o_even[0] == control) && (o_even[1] == sc))
parity = P_EVEN;
if ((o_odd[0] == control) && (o_odd[1] == sc))
parity = P_ODD;
if ((o_none[0] == control) && (o_none[1] == sc))
parity = P_NONE;
if ((o_baud[0] == control) && (o_baud[1] == sc))
baud = atoi (temp_buf);
if ((o_stop_bits_1[0] == control) &&
(o_stop_bits_2[1] == sc))
stop_bits = 1;
if ((o_stop_bits_2[0] == control) &&
(o_stop_bits_2[1] == sc))
stop_bits = 2;
if ((o_word_len_7[0] == control) && (o_word_len_7[1] == sc))
word_len = 7;
if ((o_word_len_8[0] == control) && (o_word_len_8[1] == sc))
word_len = 8;
if ((o_dtr[0] == control) && (o_dtr[1] == sc))
dtr = 1;
if ((o_xon_yes[0] == control) && (o_xon_yes[1] == sc))
xon = TRUE;
if ((o_xon_no[0] == control) && (o_xon_no[1] == sc))
xon = FALSE;
if ((o_rx_len[0] == control) && (o_rx_len[1] == sc)) {
temp_long = atol (temp_buf);
CommInterfaceOpen
89
rx_length = temp_long;
}
if ((o_tx_len[0] == control) && (o_tx_len[1] == sc)) {
temp_long = atol (temp_buf);
tx_length = temp_long;
}
}
Your implementation of this while loop may be very different.
Some switches may not apply, like the receive buffer length
switch (rx) and the send buffer length switch (tx). These
options were added to CommInterfaceOpen because the Greenleaf
CommLib supports changing these buffer sizes at run time. Your
communication package may support other unique features. If so,
make up a switch that can be used to invoke the feature. Include
the new switch in intface.c. Try to make the new switch unique
by checking the other switches in al_sys.h.
Once you have chosen a switch, it is possible to reserve it by
contacting Avid Software. Also, I am interested in supporting as
many communications packages as possible, so send in your ported
code for possible inclusion in the core product.
The 3 major pieces of CommInterfaceOpen have been described.
First, the port number or device name is saved for later use.
Next, the switches are parsed, and finally the call is made to
the communication package to open the port. However, before
showing a complete listing of CommInterfaceOpen, it is important
to understand what the first part of CommInterfaceOpen does. The
following 'if' statements allow communication ports to be
specified in 2 different ways.
/* Let valid input for device be com1 or 1, for example. */
if (sscanf (device, "com%d", &port_num) == 0) {
if (sscanf (device, "%d", &port_num) == 0) {
*info = ASINVPORT;
return(ERR_COMM_PACKAGE);
}
}
This makes it possible, for instance, to accept communication
port 1 as "com1" or as "1".
CommInterfaceOpen
90
The following 'if' statement returns an error if the
communication port number is outside the range possible for the
Greenleaf CommLib.
/* Make sure wild number did not make it through. */
if ((port_num < 1) || (port_num > 17)) {
*info = ASINVPORT;
return(ERR_COMM_PACKAGE);
}
Now that everything in CommInterfaceOpen has been described, the
following listing shows a complete version.
CommInterfaceOpen
91
/********************************************************/
int
CommInterfaceOpen (com, device, info, opts)
int com; /* The AutoLibrary communication port. */
char *device; /* The device name. */
int *info;
char *opts; /* Options. */
/********************************************************/
{
int mode, word_len, baud, stop_bits, parity, port_num, strip,
dtr, rts;
unsigned int rx_length, tx_length;
char sc, control;
char temp_buf[85];
int s_num, err;
long temp_long;
/* Start out with no errors. */
*info = ERR_OK;
/* Let valid input for device be com1 or 1 (for example) */
if (sscanf (device, "com%d", &port_num) == 0) {
if (sscanf (device, "%d", &port_num) == 0) {
*info = ASINVPORT;
return (ERR_COMM_PACKAGE);
}
}
/* Make sure wild number did not make it through. */
if ((port_num < 1) || (port_num > 17)) {
*info = ASINVPORT;
return (ERR_COMM_PACKAGE);
}
/* For Greenleaf COM1 is defined as 0. */
port_num--;
/* Save the port number for closing. */
comlist[com]->hw_port = port_num;
/* No ASCII device names in this comm package. */
comlist[com]->hw_port_name = (char *)NULL;
mode = 0;
baud = 9600;
CommInterfaceOpen
92
parity = P_ODD;
stop_bits = 1;
word_len = 8;
dtr = 0;
rts = 0;
rx_length = 8192;
tx_length = 512;
strip = ASCII;
xon = TRUE;
s_num = 0; /* Required for AvidProcessOptions. */
while ((sc = AvidProcessOptions (AVID, opts, "", &control,
temp_buf, &s_num)) != '\0') {
if ((o_strip_yes[0] == control) &&
(o_strip_yes[1] == sc))
strip = ASCII;
if ((o_strip_no[0] == control) && (o_strip_no[1] == sc))
strip = BINARY;
if ((o_even[0] == control) && (o_even[1] == sc))
parity = P_EVEN;
if ((o_odd[0] == control) && (o_odd[1] == sc))
parity = P_ODD;
if ((o_none[0] == control) && (o_none[1] == sc))
parity = P_NONE;
if ((o_baud[0] == control) && (o_baud[1] == sc))
baud = atoi (temp_buf);
if ((o_stop_bits_1[0] == control) &&
(o_stop_bits_2[1] == sc))
stop_bits = 1;
if ((o_stop_bits_2[0] == control) &&
(o_stop_bits_2[1] == sc))
stop_bits = 2;
if ((o_word_len_7[0] == control) &&
(o_word_len_7[1] == sc))
word_len = 7;
if ((o_word_len_8[0] == control) &&
(o_word_len_8[1] == sc))
CommInterfaceOpen
93
word_len = 8;
if ((o_dtr[0] == control) && (o_dtr[1] == sc))
dtr = 1;
if ((o_xon_yes[0] == control) && (o_xon_yes[1] == sc))
xon = TRUE;
if ((o_xon_no[0] == control) && (o_xon_no[1] == sc))
xon = FALSE;
if ((o_rx_len[0] == control) && (o_rx_len[1] == sc)) {
temp_long = atol (temp_buf);
rx_length = temp_long;
}
if ((o_tx_len[0] == control) && (o_tx_len[1] == sc)) {
temp_long = atol (temp_buf);
tx_length = temp_long;
}
}
mode = strip | ASINOUT | NORMALRX;
err = asiopen (comlist[com]->hw_port, mode,
rx_length, tx_length, baud, parity, stop_bits,
word_len, dtr, rts);
if (err != ASSUCCESS) {
*info = err;
return(ERR_COMM_PACKAGE);
}
if (xon) {
err = asixon(comlist[com]->hw_port, 30, 70, XON, XOFF);
if (err != ASSUCCESS) {
*info = err;
return(ERR_COMM_PACKAGE);
}
}
return(ERR_OK);
}
See Also
AvidOpenPort, Actual source code.
CommInterfaceOpen
94
CommInterfaceRead - Read Character
c = CommInterfaceRead(com, (long)r_timeout, (long)e_timeout,
(int *)&add_info, opts)
Parameter Description
int c; -- The character that was read.
int com; -- The AutoLibrary communication port.
long r_timeout; -- The repeating timeout.
long e_timeout; -- The ending timeout.
int *add_info; -- Additional return information.
char *opts; -- Options.
Options
See AvidRead
Return Codes
<Received character> -- No error occurred. The character is
returned.
ERR_COMM_PACKAGE -- This error occurs when the
communication package cannot read the
communication port correctly. When this
error occurs, the parameter 'add_info'
will contain the actual error returned
by the communication package.
Additional Information Return Codes
ERR_OK -- No error occurred.
<system err> -- When ERR_COMM_PACKAGE is returned, 'add_info'
contains the actual error returned by the
communication package.
Description
CommInterfaceRead
95
This routine is used to read from the communication port. Your
code must not call this routine directly. This routine will need
to be modified to support your communication package. See the
System Requirements section for a list of supported communication
packages.
Porting to other communication packages
You will want to refer to the final version of CommInterfaceRead
at the end of this section as you read about this routine. By
referring to the final version you will be able to see where the
many code fragments fit in.
If timeouts were not required, CommInterfaceRead would be easy.
This routine would simply return the received character, or
ERR_EOF when no character was available. The following code
shows this simple implementation.
CommInterfaceRead
96
/********************************************************/
int
CommInterfaceRead (com, r_timeout, e_timeout, info, opts)
int com; /* The AutoLibrary communication port. */
long r_timeout; /* The repeating timeout. */
long e_timeout; /* The ending timeout. */
int *info;
char *opts; /* Options. */
/********************************************************/
{
int c;
/* Start out with no errors. */
*info = ERR_OK;
c = asigetc (comlist[com]->hw_port);
if ((c >=0) && (c <= 0xFF)) {
EveryChar(c);
return(c);
}
if (c == ASINVPORT) {
*info = ASINVPORT;
return(ERR_COMM_PACKAGE);
}
if (c == ASNOTSETUP) {
*info = ASNOTSETUP;
return(ERR_COMM_PACKAGE);
}
return(ERR_EOF);
}
The above implementation would work. However, since timeouts are
required to successfully automate communications, the
AutoLibrary(tm) Program-Playback tool supports 2 types of
timeouts: Repeating Timeouts and Ending Timeouts. Let's
implement Repeating Timeouts first. It is possible to implement
Repeating Timeouts completely from within CommInterfaceRead. We
will find out later this is not possible with Ending Timeouts.
To implement Repeating Timeouts, a while loop needs to be added.
The while loop will make repeated calls to the communication
package asking for a character until a character is received or
until a timeout occurs. The following implementation supports
Repeating Timeouts.
CommInterfaceRead
97
/********************************************************/
int
CommInterfaceRead (com, r_timeout, e_timeout, info, opts)
int com; /* The AutoLibrary communication port. */
long r_timeout; /* The repeating timeout. */
long e_timeout; /* The ending timeout. */
int *info;
char *opts; /* Options. */
/********************************************************/
{
int c;
long seconds;
/* Start out with no errors. */
*info = ERR_OK;
/* Set up for Repeating Timeout. */
time(&seconds);
r_timeout = r_timeout + seconds;
while (1 > 0) {
c = asigetc (comlist[com]->hw_port);
if ((c >=0) && (c <= 0xFF)) {
EveryChar(c);
return(c);
}
if (c == ASBUFREMPTY) {
/* if still no character, check for timeout. */
time(&seconds);
if (seconds >= r_timeout) {
*info = ERR_REPEAT_TIMEOUT;
return(ERR_EOF);
}
}
}
return(ERR_EOF);
}
The call to 'time(&seconds)' gets the total number of seconds
since Jan 1, 1970. This number is added to the desired timeout
value. Say, for instance, a Repeating Timeout of 10 seconds was
CommInterfaceRead
98
specified and the current date and time is June 30, 1991 at
18:37:40. The variable 'r_timeout' would then contain
678,321,470 which is 678,321,460 plus 10, where 678,321,460 is
the number of seconds from Jan 1, 1970 to Jun 30, 1991. Once
'r_timeout' is initialized this way, it is possible to determine
when a timeout should happen. Each time 'asigetc' is called,
which results in no received character, the current system time
is compared with 'r_timeout'. If the system time is greater than
or equal to 'r_timeout', a timeout is returned.
The above implementation needs some minor but important changes.
The first change is in setting up for the Repeating Timeout.
Instead of...
time(&seconds);
r_timeout = r_timeout + seconds;
the following code is correct.
time(&seconds);
if (r_timeout < seconds)
r_timeout = r_timeout + seconds;
The 'if' test is required to support AVID_NO_TIMEOUT, which
indicates that a timeout is to never happen. AVID_NO_TIMEOUT is
defined as 2,147,483,600, which is the system time 68 years from
now. Therefore, when 'r_timeout' has this value, incrementing
'r_timeout' by 'seconds' is not needed.
The next change the above implementation needs is to return an
error if 'asigetc' returns with an error. Therefore, instead
of...
if (c == ASBUFREMPTY) {
/* if still no character, check for timeout. */
time(&seconds);
if (seconds >= r_timeout) {
*info = ERR_REPEAT_TIMEOUT;
return(ERR_EOF);
}
}
the following code is correct.
CommInterfaceRead
99
if (c == ASBUFREMPTY) {
/* if still no character, check for timeout. */
time(&seconds);
if (seconds >= r_timeout) {
*info = ERR_REPEAT_TIMEOUT;
return(ERR_EOF);
}
} else {
/* Error ASINVPORT or ASNOTSETUP occurred. */
*info = c;
return(ERR_COMM_PACKAGE);
}
This way if an error besides ASBUFREMPTY is returned,
ERR_COMM_PACKAGE is returned by CommInterfaceRead.
Finally, the last change is done for speed. A call is made to
'asigetc' before setting up for a timeout. If there is a
character, it is returned without the overhead of setting up for
a repeating timeout. If there is not a character, the time
required to set up for a timeout is ok since the code will enter
a polling loop anyway. At this point I would like to show the
complete implementation that supports Repeating Timeouts.
(Remember this implementation doesn't support Ending Timeouts).
CommInterfaceRead
100
/********************************************************/
int
CommInterfaceRead (com, r_timeout, e_timeout, info, opts)
int com; /* The AutoLibrary communication port. */
long r_timeout; /* The repeating timeout. */
long e_timeout; /* The ending timeout. */
int *info;
char *opts; /* Options. */
/********************************************************/
{
int c;
long seconds;
/* Start out with no errors. */
*info = ERR_OK;
/* Try to get a character without setting up
for a timeout. */
c = asigetc (comlist[com]->hw_port);
if ((c >=0) && (c <= 0xFF)) {
EveryChar(c);
return(c);
}
if (c == ASINVPORT) {
*info = ASINVPORT;
return(ERR_COMM_PACKAGE);
}
if (c == ASNOTSETUP) {
*info = ASNOTSETUP;
return(ERR_COMM_PACKAGE);
}
/* A timeout is required so set up for it. */
time(&seconds);
if (r_timeout < seconds)
r_timeout = r_timeout + seconds;
while (1 > 0) {
/* Try to get a character. */
c = asigetc (comlist[com]->hw_port);
if ((c >=0) && (c <= 0xFF)) {
EveryChar(c);
return(c);
}
CommInterfaceRead
101
if (c == ASBUFREMPTY) {
time (&seconds);
if (seconds >= r_timeout) {
*info = ERR_REPEAT_TIMEOUT;
return(ERR_EOF);
}
} else {
/* Error ASINVPORT or ASNOTSETUP occurred. */
*info = c;
return(ERR_COMM_PACKAGE);
}
}
opts = opts; /* for compiler */
/* Nothing should reach here but if it does... */
*info = c;
return(ERR_COMM_PACKAGE);
}
Now, Ending Timeout support needs to be added to
CommInterfaceRead. This is simple. The following test needs to
be added just inside the while loop.
/* Do not try to get a character if an ending timeout has
occurred. */
time(&seconds);
if (seconds >= e_timeout) {
*info = ERR_ENDING_TIMEOUT;
return(ERR_EOF);
}
This test also needs to occur before the first call to 'asigetc'
in case characters are continously received when an ending
timeout should occur.
Now the complete and final implementation of CommInterfaceRead
looks like the following.
CommInterfaceRead
102
/********************************************************/
int
CommInterfaceRead (com, r_timeout, e_timeout, info, opts)
int com; /* The AutoLibrary communication port. */
long r_timeout; /* The repeating timeout. */
long e_timeout; /* The ending timeout. */
int *info;
char *opts; /* Options. */
/********************************************************/
{
int c;
long seconds;
/* Start out with no errors. */
*info = ERR_OK;
/* Have to check for an ending timeout. */
time(&seconds);
if (seconds >= e_timeout) {
*info = ERR_ENDING_TIMEOUT;
return(ERR_EOF);
}
/* Try to get a character without setting up
for a timeout. */
c = asigetc (comlist[com]->hw_port);
if ((c >=0) && (c <= 0xFF)) {
EveryChar(c);
return(c);
}
if (c == ASINVPORT) {
*info = ASINVPORT;
return(ERR_COMM_PACKAGE);
}
if (c == ASNOTSETUP) {
*info = ASNOTSETUP;
return(ERR_COMM_PACKAGE);
}
/* A timeout is required so set up for it. */
time(&seconds);
if (r_timeout < seconds)
r_timeout = r_timeout + seconds;
CommInterfaceRead
103
while (1 > 0) {
/*Do not try to get a character if an ending
timeout has occurred.*/
time (&seconds);
if (seconds >= e_timeout) {
*info = ERR_ENDING_TIMEOUT;
return(ERR_EOF);
}
/* Try to get a character. */
c = asigetc (comlist[com]->hw_port);
if ((c >=0) && (c <= 0xFF)) {
EveryChar(c);
return(c);
}
if (c == ASBUFREMPTY) {
time (&seconds);
if (seconds >= r_timeout) {
*info = ERR_REPEAT_TIMEOUT;
return(ERR_EOF);
}
} else {
/* Error ASINVPORT or ASNOTSETUP occurred. */
*info = c;
return(ERR_COMM_PACKAGE);
}
}
opts = opts; /* for compiler */
/* Nothing should reach here but if it does... */
*info = c;
return(ERR_COMM_PACKAGE);
}
It was easy for CommInterfaceRead to support Ending Timeouts
because it is the responsibility of the calling routine to set up
for it. CommInterfaceRead simply gets (in the 'e_timeout'
parameter) a system time value in total seconds from Jan 1, 1970.
An Ending Timeout occurs when the current system time is greater
than or equal to 'e_timeout'.
CommInterfaceRead
104
If you would like to know more about the callers responsibility
for Ending Timeouts, take a look at the source code for
AvidSendSearch. AvidSendSearch makes calls to AvidRead from
inside a while loop. (AvidRead passes the 'r_timeout' and
'e_timeout' values directly to CommInterfaceRead). Before the
while loop, the current system time is added to the 'e_timeout'
parameter. The 'e_timeout' parameter is then constant for each
call to AvidRead, which makes it possible to support Ending
Timeouts.
See Also
AvidRead, Actual source code.
CommInterfaceRead
105
CommInterfaceSend - Send Character
err = CommInterfaceSend(com, bef, bet, s, len,
(int *)&add_info, opts)
Parameter Description
int err; -- Error code.
int com; -- The AutoLibrary communication port.
int bef; -- The number of milliseconds to delay before
sending the first character.
int bet; -- The number of milliseconds to delay between
each character.
char *s; -- The string to send.
int len; -- The length of the string to send. This value
may not equal strlen(s) because of null characters
in the string.
int *add_info; -- Additional return information.
char *opts; -- Options.
Options
See AvidSend
Return Codes
ERR_OK -- No error occurred.
ERR_COMM_PACKAGE -- This error occurs when the communication
package cannot send to the communication port
correctly. When this error occurs, the
parameter 'add_info' will contain the actual
error returned by the communication package.
Additional Information Return Codes
ERR_OK -- No error occurred.
CommInterfaceSend
106
<system err> -- When ERR_COMM_PACKAGE is returned, 'add_info'
contains the actual error returned by the
communication package.
Description
This routine is used to send characters out the communication
port. Your code must not call this routine directly. This
routine will need to be modified to support your communication
package. See the System Requirements section for a list of
supported communication packages.
Porting to other communication packages
The following sample source code is written to interface with the
Greenleaf CommLib. To support a different communication package,
use this code as a template, then code according to the
specifications of the communication package.
This routine is easy to port. A call is made to 'asiputc' inside
a 'for' loop for each character to be sent. The delay before
value is done outside of the loop, and the delay between is done
inside the 'for' loop.
CommInterfaceSend
107
/********************************************************/
int
CommInterfaceSend (com, bef, bet, s, len, info, opts)
int com; /* The AutoLibrary communication port. */
int bef; /* The number of milliseconds to delay before
sending first character. */
int bet; /* The number of milliseconds to delay between each
character. */
char *s; /* The string to send. */
int len; /* The length of the string. May not equal
strlen(s) because of null characters in the
string. */
int *info;
char *opts; /* Options. */
/********************************************************/
{
int i, status;
opts = opts; /* for compiler */
/* Start out with no errors. */
*info = ERR_OK;
/* The delay before the first character sent. */
delay (bef);
for (i=0; i<len; i++) {
/* The delay before the first character sent. */
delay (bet);
status = asiputc (comlist[com]->hw_port, s[i]);
if (status != ASSUCCESS) {
*info = status;
return(ERR_COMM_PACKAGE);
}
}
return(ERR_OK);
}
See Also
AvidSend, Actual source code.
CommInterfaceSend